From d6a2ba9083e4f537dfc39f028bd1b70ed2662b75 Mon Sep 17 00:00:00 2001 From: Fantino Davide Date: Fri, 16 Sep 2022 00:41:20 +0200 Subject: [PATCH 1/9] added reroll option --- mapvote.js | 86 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/mapvote.js b/mapvote.js index 2b5c7e1..bc4c187 100644 --- a/mapvote.js +++ b/mapvote.js @@ -11,7 +11,7 @@ function randomElement(array) { } function formatChoice(choiceIndex, mapString, currentVotes, firstBroadcast) { - return `${choiceIndex + 1}➤ ${mapString} ` + (!firstBroadcast ? `(${currentVotes})` : ""); + return `${choiceIndex}➤ ${mapString} ` + (!firstBroadcast ? `(${currentVotes})` : ""); // return `${choiceIndex + 1}❱ ${mapString} (${currentVotes} votes)` } @@ -79,6 +79,16 @@ export default class MapVote extends BasePlugin { required: false, description: 'random layer list will not include the blacklisted layers or levels. (acceptable formats: Gorodok/Gorodok_RAAS/Gorodok_AAS_v1)', default: [] + }, + hideVotesCount: { + required: false, + description: 'hides the number of votes a layer received', + default: false + }, + showRerollOption: { + required: false, + description: 'vote option to restart the vote', + default: false } }; } @@ -94,6 +104,7 @@ export default class MapVote extends BasePlugin { this.onConnectBound = false; this.broadcastIntervalTask = null; this.firstBroadcast = true; + this.newVoteTimeout = null; this.onNewGame = this.onNewGame.bind(this); this.onPlayerDisconnected = this.onPlayerDisconnected.bind(this); @@ -114,7 +125,7 @@ export default class MapVote extends BasePlugin { this.server.on('PLAYER_CONNECTED', this.setSeedingMode); this.verbose(1, 'Map vote was mounted.'); this.verbose(1, "Blacklisted Layers/Levels: " + this.options.layerLevelBlacklist.join(', ')) - await this.checkUpdates(); + // await this.checkUpdates(); // console.log("mapvote removeEventListener", this.server) } @@ -280,12 +291,15 @@ export default class MapVote extends BasePlugin { if (!isNaN(subCommand)) // if this succeeds player is voting for a map { const mapNumber = parseInt(subCommand); //try to get a vote number - if (!this.votingEnabled) { - await this.warn(steamID, "There is no vote running right now"); - return; - } - await this.registerVote(steamID, mapNumber, playerName); - this.updateNextMap(); + if (this.nominations[mapNumber]) { + if (!this.votingEnabled) { + await this.warn(steamID, "There is no vote running right now"); + return; + } + await this.registerVote(steamID, mapNumber, playerName); + this.updateNextMap(); + } else + await this.warn(steamID, "Please vote a valid option"); return; } @@ -348,8 +362,27 @@ export default class MapVote extends BasePlugin { updateNextMap() //sets next map to current mapvote winner, if there is a tie will pick at random { - const nextMap = randomElement(this.currentWinners); - this.server.rcon.execute(`AdminSetNextLayer ${nextMap}`); + let cpyWinners = this.currentWinners; + let skipSetNextMap = false; + if (cpyWinners.find(e => e == this.nominations[ 0 ])) { + if (cpyWinners.length > 1) delete cpyWinners[ cpyWinners.indexOf(this.nominations[ 0 ]).filter(e => e != null) ] + else { + skipSetNextMap = true; + if (this.newVoteTimeout == null) { + this.newVoteTimeout = setTimeout(() => { + if (this.currentWinners.find(e => e == this.nominations[ 0 ]) && this.currentWinners.length == 1) { + this.newVoteTimeout = null; + this.endVoting() + this.beginVoting(true) + } + }, 5000) + } + } + } + if (!skipSetNextMap) { + const nextMap = randomElement(cpyWinners); + this.server.rcon.execute(`AdminSetNextLayer ${nextMap}`); + } } matchLayers(builtString) { @@ -407,14 +440,14 @@ export default class MapVote extends BasePlugin { const recentlyPlayedMaps = this.objArrToValArr(this.server.layerHistory.splice(0, this.options.numberRecentMapsToExlude), "layer", "map", "name"); this.verbose(1, "Recently played maps: " + recentlyPlayedMaps.join(', ')) const all_layers = sanitizedLayers.filter((l) => l.layerid && l.map && this.options.gamemodeWhitelist.includes(l.gamemode.toUpperCase()) && (![ this.server.currentLayer ? this.server.currentLayer.map.name : null, ...recentlyPlayedMaps ].includes(l.map.name)) && !this.options.layerLevelBlacklist.find((fl) => l.layerid.toLowerCase().startsWith(fl.toLowerCase()))); - for (let i = 0; i < 6; i++) { + for (let i = 1; i <= 6; i++) { let l, maxtries = 10; do l = randomElement(all_layers); while (rnd_layers.find(lf => lf.layerid == l.layerid) && --maxtries == 0) if (maxtries > 0) { rnd_layers.push(l); - this.nominations.push(l.layerid) - this.tallies.push(0); - this.factionStrings.push(getTranslation(l.teams[ 0 ]) + "-" + getTranslation(l.teams[ 1 ])); + this.nominations[ i ] = l.layerid + this.tallies[ i ] = 0; + this.factionStrings[ i ] = getTranslation(l.teams[ 0 ]) + "-" + getTranslation(l.teams[ 1 ]); } } if (!bypassRaasFilter && rnd_layers.filter((l) => l.gamemode === 'RAAS' && this.options.gamemodeWhitelist.includes("RAAS")).length < 3) this.populateNominations(); @@ -423,19 +456,28 @@ export default class MapVote extends BasePlugin { if (cmdLayers.length <= 6) for (let cl of cmdLayers) { const cls = cl.split('_'); - const fLayers = sanitizedLayers.filter((l) => ((cls[ 0 ] == "*" || l.classname.toLowerCase().startsWith(cls[ 0 ])) && (l.gamemode.toLowerCase().startsWith(cls[ 1 ]) || (!cls[ 1 ] && [ 'RAAS', 'AAS', 'INVASION' ].includes(l.gamemode.toUpperCase()))) && (!cls[ 2 ] || l.version.toLowerCase().startsWith("v" + cls[ 2 ].replace(/v/gi, ''))))); + const fLayers = sanitizedLayers.filter((l) => ((cls[ 0 ] == "*" || l.layerid.toLowerCase().startsWith(cls[ 0 ])) && (l.gamemode.toLowerCase().startsWith(cls[ 1 ]) || (!cls[ 1 ] && [ 'RAAS', 'AAS', 'INVASION' ].includes(l.gamemode.toUpperCase()))) && (!cls[ 2 ] || l.version.toLowerCase().startsWith("v" + cls[ 2 ].replace(/v/gi, ''))))); let l; do l = randomElement(fLayers); while (rnd_layers.includes(l)) if (l) { rnd_layers.push(l); - this.nominations.push(l.layerid) - this.tallies.push(0); - this.factionStrings.push(getTranslation(l.teams[ 0 ]) + "-" + getTranslation(l.teams[ 1 ])); + this.nominations[ i ] = l.layerid + this.tallies[ i ] = 0; + this.factionStrings[ i ] = getTranslation(l.teams[ 0 ]) + "-" + getTranslation(l.teams[ 1 ]); } } else if (steamid) this.warn(steamid, "You cannot start a vote with more than 6 options"); return; } + if (this.options.showRerollOption) { + this.nominations.splice(5, 1); + this.tallies.splice(5, 1); + this.factionStrings.splice(5, 1); + this.nominations[ 0 ] = "Reroll vote list" + this.tallies[ 0 ] = 0; + this.factionStrings[ 0 ] = ""; + } + function getTranslation(t) { if (translations[ t.faction ]) return translations[ t.faction ] else { @@ -505,10 +547,12 @@ export default class MapVote extends BasePlugin { if (this.nominations.length > 0 && this.votingEnabled) { await this.broadcast("✯ MAPVOTE ✯ Vote for the next map by writing in chat the corresponding number!\n"); let nominationStrings = []; - for (let choice in this.nominations) { + for (let choice = 1; choice < this.nominations.length; choice++) { choice = Number(choice); - nominationStrings.push(formatChoice(choice, this.nominations[ choice ].replace(/\_/gi, ' ').replace(/\sv\d{1,2}/gi, '') + ' ' + this.factionStrings[ choice ], this.tallies[ choice ], this.firstBroadcast)); + let vLayer = Layers.layers.find(e => e.layerid == this.nominations[ choice ]); + nominationStrings.push(formatChoice(choice, vLayer.map.name + ' ' + vLayer.gamemode + ' ' + this.factionStrings[ choice ], this.tallies[ choice ], (this.options.hideVotesCount || this.firstBroadcast))); } + if (this.nominations[ 0 ]) nominationStrings.push(formatChoice(0, this.nominations[ 0 ], this.tallies[ 0 ], (this.options.hideVotesCount || this.firstBroadcast))) await this.broadcast(nominationStrings.join("\n")); this.firstBroadcast = false; @@ -533,7 +577,7 @@ export default class MapVote extends BasePlugin { //counts a vote from a player and adds it to tallies async registerVote(steamID, nominationIndex, playerName) { - nominationIndex -= 1; // shift indices from display range + // nominationIndex -= 1; // shift indices from display range if (nominationIndex < 0 || nominationIndex > this.nominations.length) { await this.warn(steamID, `[Map Vote] ${playerName}: invalid map number, typ !vote results to see map numbers`); return; From 75ef808991363b18fa58005ae129055ba20dcabd Mon Sep 17 00:00:00 2001 From: Fantino Davide Date: Fri, 16 Sep 2022 01:04:04 +0200 Subject: [PATCH 2/9] working reroll option --- mapvote.js | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/mapvote.js b/mapvote.js index bc4c187..acbfaa1 100644 --- a/mapvote.js +++ b/mapvote.js @@ -291,7 +291,7 @@ export default class MapVote extends BasePlugin { if (!isNaN(subCommand)) // if this succeeds player is voting for a map { const mapNumber = parseInt(subCommand); //try to get a vote number - if (this.nominations[mapNumber]) { + if (this.nominations[ mapNumber ]) { if (!this.votingEnabled) { await this.warn(steamID, "There is no vote running right now"); return; @@ -375,7 +375,7 @@ export default class MapVote extends BasePlugin { this.endVoting() this.beginVoting(true) } - }, 5000) + }, 2 * 60 * 1000) } } } @@ -452,8 +452,14 @@ export default class MapVote extends BasePlugin { } if (!bypassRaasFilter && rnd_layers.filter((l) => l.gamemode === 'RAAS' && this.options.gamemodeWhitelist.includes("RAAS")).length < 3) this.populateNominations(); } else { - if (cmdLayers.length == 1 && cmdLayers[ 0 ].split('_')[ 0 ] == "*") for (let i = 0; i < 5; i++) cmdLayers.push(cmdLayers[ 0 ]) - if (cmdLayers.length <= 6) + const maxOptions = this.options.showRerollOption ? 5 : 6; + let singleGamemodeVote = false; + if (cmdLayers.length == 1 && cmdLayers[ 0 ].split('_')[ 0 ] == "*") { + singleGamemodeVote = true; + for (let i = 0; i < maxOptions; i++) cmdLayers.push(cmdLayers[ 0 ]) + } + if (singleGamemodeVote || cmdLayers.length <= maxOptions) { + let i = 1; for (let cl of cmdLayers) { const cls = cl.split('_'); const fLayers = sanitizedLayers.filter((l) => ((cls[ 0 ] == "*" || l.layerid.toLowerCase().startsWith(cls[ 0 ])) && (l.gamemode.toLowerCase().startsWith(cls[ 1 ]) || (!cls[ 1 ] && [ 'RAAS', 'AAS', 'INVASION' ].includes(l.gamemode.toUpperCase()))) && (!cls[ 2 ] || l.version.toLowerCase().startsWith("v" + cls[ 2 ].replace(/v/gi, ''))))); @@ -464,16 +470,23 @@ export default class MapVote extends BasePlugin { this.nominations[ i ] = l.layerid this.tallies[ i ] = 0; this.factionStrings[ i ] = getTranslation(l.teams[ 0 ]) + "-" + getTranslation(l.teams[ 1 ]); + i++; } } - else if (steamid) this.warn(steamid, "You cannot start a vote with more than 6 options"); return; + } + else if (steamid) { + this.warn(steamid, "You cannot start a vote with more than " + maxOptions + " options"); + return; + } } if (this.options.showRerollOption) { - this.nominations.splice(5, 1); - this.tallies.splice(5, 1); - this.factionStrings.splice(5, 1); - this.nominations[ 0 ] = "Reroll vote list" + if (this.nominations.length > 5) { + this.nominations.splice(5, 1); + this.tallies.splice(5, 1); + this.factionStrings.splice(5, 1); + } + this.nominations[ 0 ] = "Reroll vote list with random options" this.tallies[ 0 ] = 0; this.factionStrings[ 0 ] = ""; } @@ -526,6 +539,8 @@ export default class MapVote extends BasePlugin { endVoting() { this.votingEnabled = false; clearInterval(this.broadcastIntervalTask); + clearTimeout(this.newVoteTimeout); + this.newVoteTimeout = null; this.broadcastIntervalTask = null; } objArrToValArr(arr, ...key) { @@ -589,7 +604,7 @@ export default class MapVote extends BasePlugin { this.tallies[ nominationIndex ] += 1; if (previousVote !== undefined) this.tallies[ previousVote ] -= 1; - await this.warn(steamID, `Registered vote: ${this.nominations[ nominationIndex ].replace(/\_/gi, ' ').replace(/\sv\d{1,2}/gi, '')} ${this.factionStrings[ nominationIndex ]} (${this.tallies[ nominationIndex ]} votes)`); + await this.warn(steamID, `Registered vote: ${this.nominations[ nominationIndex ].replace(/\_/gi, ' ').replace(/\sv\d{1,2}/gi, '')} ${this.factionStrings[ nominationIndex ]} ` + (this.options.hideVotesCount ? `` : `(${this.tallies[ nominationIndex ]} votes)`)); // await this.msgDirect(steamID, `Registered vote`);// ${this.nominations[ nominationIndex ]} ${this.factionStrings[ nominationIndex ]} (${this.tallies[ nominationIndex ]} votes)`); // await this.msgDirect(steamID, `${this.nominations[ nominationIndex ]} (${this.tallies[ nominationIndex ]} votes)`); // await this.msgDirect(steamID, `${this.factionStrings[ nominationIndex ]}`); From 54e572a2d133909d9aa1b519c2bdfde804e02396 Mon Sep 17 00:00:00 2001 From: Fantino Davide Date: Fri, 16 Sep 2022 01:07:54 +0200 Subject: [PATCH 3/9] updated documentation --- README.MD | 18 +++++++++++++++++- mapvote.js | 4 ++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/README.MD b/README.MD index b0d9091..eca8b5b 100644 --- a/README.MD +++ b/README.MD @@ -83,6 +83,20 @@ The random layer list will not include the blacklisted layers or levels. (accept ``` [] ``` +#### hideVotesCount +###### Description +Hides the number of votes a layer received in broadcast message. +###### Default +```json +false +``` +#### showRerollOption +###### Description +vote option to restart the vote with random entries. +###### Default +```json +false +``` ### Example configuration ```json { @@ -94,6 +108,8 @@ The random layer list will not include the blacklisted layers or levels. (accept "numberRecentMapsToExlude": 4, "automaticSeedingMode": true, "gamemodeWhitelist": [ "AAS", "RAAS", "Invasion" ], - "layerLevelBlacklist": [ "BlackCoast_Seed" ] + "layerLevelBlacklist": [ "BlackCoast_Seed" ], + "hideVotesCount": false, + "showRerollOption": false } ``` diff --git a/mapvote.js b/mapvote.js index acbfaa1..66466ca 100644 --- a/mapvote.js +++ b/mapvote.js @@ -82,12 +82,12 @@ export default class MapVote extends BasePlugin { }, hideVotesCount: { required: false, - description: 'hides the number of votes a layer received', + description: 'hides the number of votes a layer received in broadcast message', default: false }, showRerollOption: { required: false, - description: 'vote option to restart the vote', + description: 'vote option to restart the vote with random entries', default: false } }; From dc3f294a90bcd27f4ecc323cf5d79d9bed58447b Mon Sep 17 00:00:00 2001 From: Fantino Davide Date: Fri, 16 Sep 2022 01:16:04 +0200 Subject: [PATCH 4/9] hotfix --- mapvote.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mapvote.js b/mapvote.js index 66466ca..e561811 100644 --- a/mapvote.js +++ b/mapvote.js @@ -365,7 +365,10 @@ export default class MapVote extends BasePlugin { let cpyWinners = this.currentWinners; let skipSetNextMap = false; if (cpyWinners.find(e => e == this.nominations[ 0 ])) { - if (cpyWinners.length > 1) delete cpyWinners[ cpyWinners.indexOf(this.nominations[ 0 ]).filter(e => e != null) ] + if (cpyWinners.length > 1) { + delete cpyWinners[ cpyWinners.indexOf(this.nominations[ 0 ]) ] + cpyWinners = cpyWinners.filter(e => e != null) + } else { skipSetNextMap = true; if (this.newVoteTimeout == null) { From 7a22a78add9f543fdc8b399b0a5063e1ae5adcaf Mon Sep 17 00:00:00 2001 From: Fantino Davide Date: Fri, 16 Sep 2022 12:20:18 +0200 Subject: [PATCH 5/9] update --- mapvote.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mapvote.js b/mapvote.js index e561811..e0ec9a1 100644 --- a/mapvote.js +++ b/mapvote.js @@ -1,4 +1,4 @@ -//Plugin by MaskedMonkeyMan +//Plugin reworked by JetDave, original version by MaskedMonkeyMan import BasePlugin from "./base-plugin.js"; From 0e7fd4a1234ce3c43e78f087c3d16e81acc5158c Mon Sep 17 00:00:00 2001 From: Davide Fantino <80767709+fantinodavide@users.noreply.github.com> Date: Fri, 16 Sep 2022 16:12:48 +0200 Subject: [PATCH 6/9] hotfix --- mapvote.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mapvote.js b/mapvote.js index e0ec9a1..39a3c37 100644 --- a/mapvote.js +++ b/mapvote.js @@ -249,8 +249,8 @@ export default class MapVote extends BasePlugin { if (this.server.players.length >= 1 && this.server.players.length < 40) { const seedingMaps = Layers.layers.filter((l) => l.layerid && l.gamemode.toUpperCase() == "SEED" && !this.options.layerLevelBlacklist.find((fl) => l.layerid.toLowerCase().startsWith(fl.toLowerCase()))) + const rndMap = randomElement(seedingMaps); if (this.server.currentLayer) { - const rndMap = randomElement(seedingMaps); if (this.server.currentLayer.gamemode.toLowerCase() != "seed") { if (this.server.players.length <= 5) { const newCurrentMap = rndMap.layerid; From 2010dffbdf3bb4f97fe3c7b3a623800c5ca80563 Mon Sep 17 00:00:00 2001 From: Davide Fantino <80767709+fantinodavide@users.noreply.github.com> Date: Fri, 16 Sep 2022 16:29:35 +0200 Subject: [PATCH 7/9] hotfix --- mapvote.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mapvote.js b/mapvote.js index 39a3c37..a966786 100644 --- a/mapvote.js +++ b/mapvote.js @@ -517,13 +517,14 @@ export default class MapVote extends BasePlugin { if (playerCount < minPlayers && !force) { if (this.onConnectBound == false) { - this.server.on("PLAYER_CONNECTED", () => { this.beginVoting }) + this.server.on("PLAYER_CONNECTED", this.beginVoting) this.onConnectBound = true; } return; } if (this.onConnectBound) { - this.server.removeEventListener("PLAYER_CONNECTED", () => { this.beginVoting }); + + this.server.removeEventListener("PLAYER_CONNECTED", this.beginVoting); this.onConnectBound = false; } From 09bae31e416bc0b0dfedb851b1dfde4eec933178 Mon Sep 17 00:00:00 2001 From: Davide Fantino <80767709+fantinodavide@users.noreply.github.com> Date: Fri, 16 Sep 2022 20:35:08 +0200 Subject: [PATCH 8/9] hotfix --- mapvote.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/mapvote.js b/mapvote.js index a966786..d70742c 100644 --- a/mapvote.js +++ b/mapvote.js @@ -105,6 +105,11 @@ export default class MapVote extends BasePlugin { this.broadcastIntervalTask = null; this.firstBroadcast = true; this.newVoteTimeout = null; + this.newVoteOptions = { + steamid: null, + cmdLayers: [], + bypassRaasFilter: false + }; this.onNewGame = this.onNewGame.bind(this); this.onPlayerDisconnected = this.onPlayerDisconnected.bind(this); @@ -376,9 +381,10 @@ export default class MapVote extends BasePlugin { if (this.currentWinners.find(e => e == this.nominations[ 0 ]) && this.currentWinners.length == 1) { this.newVoteTimeout = null; this.endVoting() - this.beginVoting(true) + this.beginVoting(true, this.newVoteOptions.steamid, this.newVoteOptions.cmdLayers) } }, 2 * 60 * 1000) + setTimeout(this.broadcastNominations, 1 * 60 * 1000) } } } @@ -485,13 +491,19 @@ export default class MapVote extends BasePlugin { if (this.options.showRerollOption) { if (this.nominations.length > 5) { - this.nominations.splice(5, 1); - this.tallies.splice(5, 1); - this.factionStrings.splice(5, 1); + this.nominations.splice(6, 1); + this.tallies.splice(6, 1); + this.factionStrings.splice(6, 1); } + + this.newVoteOptions.steamid = steamid; + this.newVoteOptions.bypassRaasFilter = bypassRaasFilter; + this.newVoteOptions.cmdLayers = cmdLayers; + this.nominations[ 0 ] = "Reroll vote list with random options" this.tallies[ 0 ] = 0; this.factionStrings[ 0 ] = ""; + } function getTranslation(t) { @@ -523,7 +535,7 @@ export default class MapVote extends BasePlugin { return; } if (this.onConnectBound) { - + this.server.removeEventListener("PLAYER_CONNECTED", this.beginVoting); this.onConnectBound = false; } From 4b0131a8e81ce9ccc41db801c7f2c07ba494b069 Mon Sep 17 00:00:00 2001 From: Davide Fantino <80767709+fantinodavide@users.noreply.github.com> Date: Fri, 16 Sep 2022 22:41:55 +0200 Subject: [PATCH 9/9] added voteBroadcastMessage --- README.MD | 10 +++++++++- mapvote.js | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/README.MD b/README.MD index eca8b5b..92dc45b 100644 --- a/README.MD +++ b/README.MD @@ -97,6 +97,13 @@ vote option to restart the vote with random entries. ```json false ``` +#### voteBroadcastMessage +###### Description +Message that is sent as broadcast to announce a vote. +###### Default +``` +✯ MAPVOTE ✯ Vote for the next map by writing in chat the corresponding number! +``` ### Example configuration ```json { @@ -110,6 +117,7 @@ false "gamemodeWhitelist": [ "AAS", "RAAS", "Invasion" ], "layerLevelBlacklist": [ "BlackCoast_Seed" ], "hideVotesCount": false, - "showRerollOption": false + "showRerollOption": false, + "voteBroadcastMessage": "✯ MAPVOTE ✯ Vote for the next map by writing in chat the corresponding number!" } ``` diff --git a/mapvote.js b/mapvote.js index d70742c..0f28b74 100644 --- a/mapvote.js +++ b/mapvote.js @@ -89,6 +89,11 @@ export default class MapVote extends BasePlugin { required: false, description: 'vote option to restart the vote with random entries', default: false + }, + voteBroadcastMessage: { + required: false, + description: 'Message that is sent as broadcast to announce a vote', + default: "✯ MAPVOTE ✯ Vote for the next map by writing in chat the corresponding number!" } }; } @@ -576,7 +581,7 @@ export default class MapVote extends BasePlugin { //Note: broadcast strings with multi lines are very strange async broadcastNominations() { if (this.nominations.length > 0 && this.votingEnabled) { - await this.broadcast("✯ MAPVOTE ✯ Vote for the next map by writing in chat the corresponding number!\n"); + await this.broadcast(this.options.voteBroadcastMessage); let nominationStrings = []; for (let choice = 1; choice < this.nominations.length; choice++) { choice = Number(choice);