Question Giveaway started by " + Tools.escapeHTML(giveaway.host.name) + "" +
@@ -390,7 +390,7 @@ let commands = {
case 'game':
case 'giveaway':
case 'user':
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
reply = '
Giveaway participation commands: (start with /giveaway, except for /ga)
' +
'- guess or /ga
answer - Guesses the answer for a question giveaway
' +
'- viewanswer - Shows the answer in a question giveaway (only to host/giver)
' +
@@ -399,7 +399,7 @@ let commands = {
'- leave or leavelottery - Leaves a lottery giveaway
';
break;
default:
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
reply = '
Wi-Fi room Giveaway help and info' +
'- help user - shows list of participation commands
' +
'- help staff - shows giveaway staff commands (Requires: % @ # & ~)';
diff --git a/command-parser.js b/command-parser.js
index fb4128ce92..4efafa36aa 100644
--- a/command-parser.js
+++ b/command-parser.js
@@ -170,31 +170,54 @@ class CommandContext {
}
return true;
}
- canBroadcast(checkOnly, suppressMessage) {
- let message = this.canTalk(this.message);
- if (!message) return false;
- let normalized = message.toLowerCase().replace(/[^a-z0-9\s!,]/g, '');
-
+ canBroadcast() {
if (!this.broadcasting && this.cmdToken === BROADCAST_TOKEN) {
+ if (this.user.broadcasting) {
+ this.errorReply("You can't broadcast another command too soon.");
+ return false;
+ }
+
+ let message = this.canTalk(this.message);
+ if (!message) return false;
if (!this.user.can('broadcast', null, this.room)) {
this.errorReply("You need to be voiced to broadcast this command's information.");
- this.errorReply("To see it for yourself, use: /" + message.substr(1));
+ this.errorReply("To see it for yourself, use: /" + this.message.substr(1));
return false;
}
// broadcast cooldown
- if (this.room.lastBroadcast === normalized &&
+ let broadcastMessage = message.toLowerCase().replace(/[^a-z0-9\s!,]/g, '');
+
+ if (this.room.lastBroadcast === this.broadcastMessage &&
this.room.lastBroadcastTime >= Date.now() - BROADCAST_COOLDOWN) {
this.errorReply("You can't broadcast this because it was just broadcast.");
return false;
}
- this.broadcasting = true;
+
+ this.message = message;
+ this.broadcastMessage = broadcastMessage;
+ this.user.broadcasting = true;
}
- if (this.broadcasting && !checkOnly) {
- this.add('|c|' + this.user.getIdentity(this.room.id) + '|' + (suppressMessage || message));
- this.room.lastBroadcast = normalized;
- this.room.lastBroadcastTime = Date.now();
+ return true;
+ }
+ runBroadcast(suppressMessage) {
+ if (this.broadcasting || this.cmdToken !== BROADCAST_TOKEN) {
+ // Already being broadcast, or the user doesn't intend to broadcast.
+ return true;
}
+
+ if (!this.broadcastMessage) {
+ // Permission hasn't been checked yet. Do it now.
+ if (!this.canBroadcast()) return false;
+ }
+
+ this.add('|c|' + this.user.getIdentity(this.room.id) + '|' + (suppressMessage || this.message));
+ this.room.lastBroadcast = this.broadcastMessage;
+ this.room.lastBroadcastTime = Date.now();
+
+ this.broadcasting = true;
+ this.user.broadcasting = false;
+
return true;
}
parse(message, inNamespace, room) {
diff --git a/commands.js b/commands.js
index cd001e24f6..a3d89a3014 100644
--- a/commands.js
+++ b/commands.js
@@ -25,7 +25,7 @@ const HOURMUTE_LENGTH = 60 * 60 * 1000;
exports.commands = {
version: function (target, room, user) {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
this.sendReplyBox("Server version:
" + CommandParser.package.version + "");
},
@@ -594,7 +594,7 @@ exports.commands = {
roomdesc: function (target, room, user) {
if (!target) {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
if (!room.desc) return this.sendReply("This room does not have a description set.");
this.sendReplyBox("The room description is: " + Tools.escapeHTML(room.desc));
return;
@@ -627,7 +627,7 @@ exports.commands = {
topic: 'roomintro',
roomintro: function (target, room, user) {
if (!target) {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
if (!room.introMessage) return this.sendReply("This room does not have an introduction set.");
this.sendReply('|raw|
' + room.introMessage + '
');
if (!this.broadcasting && user.can('declare', null, room)) {
@@ -696,7 +696,7 @@ exports.commands = {
roomalias: function (target, room, user) {
if (!target) {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
if (!room.aliases || !room.aliases.length) return this.sendReplyBox("This room does not have any aliases.");
return this.sendReplyBox("This room has the following aliases: " + room.aliases.join(", ") + "");
}
@@ -2241,7 +2241,7 @@ exports.commands = {
if (!user.hasConsoleAccess(connection)) {
return this.errorReply("/eval - Access denied.");
}
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
if (!this.broadcasting) this.sendReply('||>> ' + target);
try {
@@ -2259,7 +2259,7 @@ exports.commands = {
if (!user.hasConsoleAccess(connection)) {
return this.errorReply("/evalbattle - Access denied.");
}
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
if (!room.battle) {
return this.errorReply("/evalbattle - This isn't a battle room.");
}
diff --git a/tournaments/index.js b/tournaments/index.js
index f761feb964..6a2e7b43b3 100644
--- a/tournaments/index.js
+++ b/tournaments/index.js
@@ -806,7 +806,7 @@ let commands = {
}
},
getusers: function (tournament) {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
let users = usersToNames(tournament.generator.getUsers(true).sort());
this.sendReplyBox("
" + users.length + " users remain in this tournament:" + Tools.escapeHTML(users.join(", ")));
},
@@ -993,7 +993,7 @@ CommandParser.commands.tournament = function (paramString, room, user) {
if (!params[0]) params = [];
if (cmd === '') {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
this.sendReply('|tournaments|info|' + JSON.stringify(Object.keys(exports.tournaments).filter(tournament => {
tournament = exports.tournaments[tournament];
return !tournament.room.isPrivate && !tournament.room.isPersonal && !tournament.room.staffRoom;
@@ -1112,7 +1112,7 @@ CommandParser.commands.tournament = function (paramString, room, user) {
}
};
CommandParser.commands.tournamenthelp = function (target, room, user) {
- if (!this.canBroadcast()) return;
+ if (!this.runBroadcast()) return;
return this.sendReplyBox(
"- create/new <format>, <type> [, <comma-separated arguments>]: Creates a new tournament in the current room.
" +
"- settype <type> [, <comma-separated arguments>]: Modifies the type of tournament after it's been created, but before it has started.
" +
diff --git a/users.js b/users.js
index 90c5614e49..2e241ed0c3 100644
--- a/users.js
+++ b/users.js
@@ -431,6 +431,7 @@ class User {
this.chatQueue = null;
this.chatQueueTimeout = null;
this.lastChatMessage = 0;
+ this.broadcasting = false;
// for the anti-spamming mechanism
this.lastMessage = '';