Ticket #3383: lobby_coding_convention_v1.patch
File lobby_coding_convention_v1.patch, 23.3 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/gui/lobby/lobby.js
1 const g_MapTypesText = [translateWithContext("map", "Skirmish"), translateWithContext("map", "Random"), translate("Scenario")]; 2 const g_MapTypes = ["skirmish", "random", "scenario"]; 3 const g_ShowTimestamp = Engine.ConfigDB_GetValue("user", "lobby.chattimestamp") == "true"; 4 const g_ModPrefix = "@"; 5 const g_SpecialKey = Math.random(); 6 const g_SpamBlockLength = 30; // Block spammers for 30 seconds. 7 1 8 var g_ChatMessages = []; 2 9 var g_Name = "unknown"; 3 10 var g_GameList = {} 4 11 var g_GameListSortBy = "name"; 5 12 var g_PlayerListSortBy = "name"; 6 13 var g_GameListOrder = 1; // 1 for ascending sort, and -1 for descending 7 14 var g_PlayerListOrder = 1; 8 var g_specialKey = Math.random();9 15 // This object looks like {"name":[numMessagesSinceReset, lastReset, timeBlocked]} when in use. 10 var g_spamMonitor = {}; 11 var g_timestamp = Engine.ConfigDB_GetValue("user", "lobby.chattimestamp") == "true"; 12 var g_mapSizes = {}; 13 const g_mapTypesText = [translateWithContext("map", "Skirmish"), translateWithContext("map", "Random"), translate("Scenario")]; 14 const g_mapTypes = ["skirmish", "random", "scenario"]; 15 var g_userRating = ""; // Rating of user, defaults to Unrated 16 var g_modPrefix = "@"; 17 // Block spammers for 30 seconds. 18 var SPAM_BLOCK_LENGTH = 30; 16 var g_SpamMonitor = {}; 17 var g_MapSizes = {}; 18 var g_UserRating = ""; // Rating of user, defaults to Unrated 19 19 20 20 //////////////////////////////////////////////////////////////////////////////////////////////// 21 21 22 22 function init(attribs) 23 23 { … … 25 25 initMusic(); 26 26 global.music.setState(global.music.states.MENU); 27 27 28 28 g_Name = Engine.LobbyGetNick(); 29 29 30 g_ mapSizes = initMapSizes();31 g_ mapSizes.shortNames.splice(0, 0, translateWithContext("map size", "Any"));32 g_ mapSizes.tiles.splice(0, 0, "");30 g_MapSizes = initMapSizes(); 31 g_MapSizes.shortNames.splice(0, 0, translateWithContext("map size", "Any")); 32 g_MapSizes.tiles.splice(0, 0, ""); 33 33 34 34 var mapSizeFilter = Engine.GetGUIObjectByName("mapSizeFilter"); 35 mapSizeFilter.list = g_ mapSizes.shortNames;36 mapSizeFilter.list_data = g_ mapSizes.tiles;35 mapSizeFilter.list = g_MapSizes.shortNames; 36 mapSizeFilter.list_data = g_MapSizes.tiles; 37 37 38 38 var playersNumberFilter = Engine.GetGUIObjectByName("playersNumberFilter"); 39 39 playersNumberFilter.list = [translateWithContext("player number", "Any"),2,3,4,5,6,7,8]; 40 40 playersNumberFilter.list_data = ["",2,3,4,5,6,7,8]; 41 41 42 42 var mapTypeFilter = Engine.GetGUIObjectByName("mapTypeFilter"); 43 mapTypeFilter.list = [translateWithContext("map", "Any")].concat(g_ mapTypesText);44 mapTypeFilter.list_data = [""].concat(g_ mapTypes);43 mapTypeFilter.list = [translateWithContext("map", "Any")].concat(g_MapTypesText); 44 mapTypeFilter.list_data = [""].concat(g_MapTypes); 45 45 46 46 Engine.LobbySetPlayerPresence("available"); 47 47 Engine.SendGetGameList(); 48 48 Engine.SendGetBoardList(); 49 49 updatePlayerList(); … … 208 208 }); 209 209 for (var i = 0; i < cleanPlayerList.length; i++) 210 210 { 211 211 // Identify current user's rating. 212 212 if (cleanPlayerList[i].name == g_Name && cleanPlayerList[i].rating) 213 g_ userRating = cleanPlayerList[i].rating;213 g_UserRating = cleanPlayerList[i].rating; 214 214 // Add a "-" for unrated players. 215 215 if (!cleanPlayerList[i].rating) 216 216 cleanPlayerList[i].rating = "-"; 217 217 // Colorize. 218 218 var [name, status, rating] = formatPlayerListEntry(cleanPlayerList[i].name, cleanPlayerList[i].presence, cleanPlayerList[i].rating, cleanPlayerList[i].role); … … 236 236 237 237 /** 238 238 * Display the profile of the selected player. 239 239 * Displays N/A for all stats until updateProfile is called when the stats 240 240 * are actually received from the bot. 241 * 241 * 242 242 * @param caller From which screen is the user requesting data from? 243 243 */ 244 244 function displayProfile(caller) 245 245 { 246 246 var playerList, rating; … … 261 261 Engine.GetGUIObjectByName("profileArea").hidden = true; 262 262 return; 263 263 } 264 264 Engine.GetGUIObjectByName("profileArea").hidden = false; 265 265 266 Engine.SendGetProfile(playerList.list[playerList.selected]); 266 Engine.SendGetProfile(playerList.list[playerList.selected]); 267 267 268 268 var user = playerList.list_name[playerList.selected]; 269 269 var role = Engine.LobbyGetPlayerRole(playerList.list[playerList.selected]); 270 270 var userList = Engine.GetGUIObjectByName("playersBox"); 271 271 if (role && caller == "lobbylist") … … 306 306 Engine.GetGUIObjectByName("profileErrorText").hidden = false; 307 307 return; 308 308 } 309 309 Engine.GetGUIObjectByName("profileWindowArea").hidden = false; 310 310 Engine.GetGUIObjectByName("profileErrorText").hidden = true; 311 311 312 312 if (attributes[0].rating != "") 313 user = sprintf(translate("%(nick)s (%(rating)s)"), { nick: user, rating: attributes[0].rating });313 user = sprintf(translate("%(nick)s (%(rating)s)"), { "nick": user, "rating": attributes[0].rating }); 314 314 315 315 Engine.GetGUIObjectByName("profileUsernameText").caption = user; 316 316 Engine.GetGUIObjectByName("profileRankText").caption = attributes[0].rank; 317 317 Engine.GetGUIObjectByName("profileHighestRatingText").caption = attributes[0].highestRating; 318 318 Engine.GetGUIObjectByName("profileTotalGamesText").caption = attributes[0].totalGamesPlayed; 319 319 Engine.GetGUIObjectByName("profileWinsText").caption = attributes[0].wins; 320 320 Engine.GetGUIObjectByName("profileLossesText").caption = attributes[0].losses; 321 321 322 322 var winRate = (attributes[0].wins / attributes[0].totalGamesPlayed * 100).toFixed(2); 323 323 if (attributes[0].totalGamesPlayed != 0) 324 Engine.GetGUIObjectByName("profileRatioText").caption = sprintf(translate("%(percentage)s%%"), { percentage: winRate });324 Engine.GetGUIObjectByName("profileRatioText").caption = sprintf(translate("%(percentage)s%%"), { "percentage": winRate }); 325 325 else 326 326 Engine.GetGUIObjectByName("profileRatioText").caption = translateWithContext("Used for an undefined winning rate", "-"); 327 327 return; 328 328 } 329 329 else if (!Engine.GetGUIObjectByName("leaderboard").hidden) 330 330 playerList = Engine.GetGUIObjectByName("leaderboardBox"); 331 331 else 332 332 playerList = Engine.GetGUIObjectByName("playersBox"); 333 333 334 334 if (attributes[0].rating == "-2") 335 335 return; 336 336 // Make sure the stats we have received coincide with the selected player. 337 337 if (attributes[0].player != playerList.list[playerList.selected]) 338 338 return; 339 339 user = playerList.list_name[playerList.selected]; 340 340 if (attributes[0].rating != "") 341 user = sprintf(translate("%(nick)s (%(rating)s)"), { nick: user, rating: attributes[0].rating });341 user = sprintf(translate("%(nick)s (%(rating)s)"), { "nick": user, "rating": attributes[0].rating }); 342 342 343 343 Engine.GetGUIObjectByName("usernameText").caption = user; 344 344 Engine.GetGUIObjectByName("rankText").caption = attributes[0].rank; 345 345 Engine.GetGUIObjectByName("highestRatingText").caption = attributes[0].highestRating; 346 346 Engine.GetGUIObjectByName("totalGamesText").caption = attributes[0].totalGamesPlayed; 347 347 Engine.GetGUIObjectByName("winsText").caption = attributes[0].wins; 348 348 Engine.GetGUIObjectByName("lossesText").caption = attributes[0].losses; 349 349 350 350 var winRate = (attributes[0].wins / attributes[0].totalGamesPlayed * 100).toFixed(2); 351 351 if (attributes[0].totalGamesPlayed != 0) 352 Engine.GetGUIObjectByName("ratioText").caption = sprintf(translate("%(percentage)s%%"), { percentage: winRate });352 Engine.GetGUIObjectByName("ratioText").caption = sprintf(translate("%(percentage)s%%"), { "percentage": winRate }); 353 353 else 354 354 Engine.GetGUIObjectByName("ratioText").caption = translateWithContext("Used for an undefined winning rate", "-"); 355 355 } 356 356 357 357 /** … … 467 467 name = '[color="255 0 0"]' + name + '[/color]'; 468 468 list_name.push(name); 469 469 list_ip.push(g.ip); 470 470 list_mapName.push(translate(g.niceMapName)); 471 471 list_mapSize.push(translatedMapSize(g.mapSize)); 472 let idx = g_ mapTypes.indexOf(g.mapType);473 list_mapType.push(idx != -1 ? g_ mapTypesText[idx] : "");472 let idx = g_MapTypes.indexOf(g.mapType); 473 list_mapType.push(idx != -1 ? g_MapTypesText[idx] : ""); 474 474 list_nPlayers.push(g.nbp + "/" +g.tnbp); 475 475 list.push(name); 476 476 list_data.push(c); 477 477 } 478 478 c++; … … 524 524 case "offline": 525 525 color = "0 0 0"; 526 526 status = translate("Offline"); 527 527 break; 528 528 default: 529 warn(sprintf("Unknown presence '%(presence)s'", { presence: presence }));529 warn(sprintf("Unknown presence '%(presence)s'", { "presence": presence })); 530 530 color = "178 178 178"; 531 531 status = translateWithContext("lobby presence", "Unknown"); 532 532 break; 533 533 } 534 534 // Center the unrated symbol. … … 536 536 rating = " -"; 537 537 var formattedStatus = '[color="' + color + '"]' + status + "[/color]"; 538 538 var formattedRating = '[color="' + color + '"]' + rating + "[/color]"; 539 539 var role = Engine.LobbyGetPlayerRole(nickname); 540 540 if (role == "moderator") 541 nickname = g_ modPrefix + nickname;541 nickname = g_ModPrefix + nickname; 542 542 var formattedName = colorPlayerName(nickname); 543 543 544 544 // Push this player's name and status onto the list 545 545 return [formattedName, formattedStatus, formattedRating]; 546 546 } … … 552 552 function translatedMapSize(mapSize) 553 553 { 554 554 if (+mapSize !== +mapSize) // NaN 555 555 return translate(mapSize); 556 556 else 557 return g_ mapSizes.shortNames[g_mapSizes.tiles.indexOf(+mapSize)];557 return g_MapSizes.shortNames[g_MapSizes.tiles.indexOf(+mapSize)]; 558 558 } 559 559 560 560 /** 561 561 * Populate the game info area with information on the current game selection. 562 562 */ … … 575 575 var mapData; 576 576 var g = Engine.GetGUIObjectByName("gamesBox").list_data[selected]; 577 577 578 578 // Load map data 579 579 if (g_GameList[g].mapType == "random" && g_GameList[g].mapName == "random") 580 mapData = { "settings": {"Description": translate("A randomly selected map.")}};580 mapData = { "settings": { "Description": translate("A randomly selected map.") } }; 581 581 else if (g_GameList[g].mapType == "random" && Engine.FileExists(g_GameList[g].mapName + ".json")) 582 582 mapData = Engine.ReadJSONFile(g_GameList[g].mapName + ".json"); 583 583 else if (Engine.FileExists(g_GameList[g].mapName + ".xml")) 584 584 mapData = Engine.LoadMapSettings(g_GameList[g].mapName + ".xml"); 585 585 else 586 // Warn the player if we can't find the map. 587 warn(sprintf("Map '%(mapName)s' not found locally.", { mapName: g_GameList[g].mapName }));586 // Warn the player if we can't find the map. 587 warn(sprintf("Map '%(mapName)s' not found locally.", { "mapName": g_GameList[g].mapName })); 588 588 589 589 // Show the game info panel and join button. 590 590 Engine.GetGUIObjectByName("gameInfo").hidden = false; 591 591 Engine.GetGUIObjectByName("joinGameButton").hidden = false; 592 592 Engine.GetGUIObjectByName("gameInfoEmpty").hidden = true; … … 594 594 // Display the map name, number of players, the names of the players, the map size and the map type. 595 595 Engine.GetGUIObjectByName("sgMapName").caption = translate(g_GameList[g].niceMapName); 596 596 Engine.GetGUIObjectByName("sgNbPlayers").caption = g_GameList[g].nbp + "/" + g_GameList[g].tnbp; 597 597 Engine.GetGUIObjectByName("sgPlayersNames").caption = g_GameList[g].players; 598 598 Engine.GetGUIObjectByName("sgMapSize").caption = translatedMapSize(g_GameList[g].mapSize); 599 let idx = g_ mapTypes.indexOf(g_GameList[g].mapType);600 Engine.GetGUIObjectByName("sgMapType").caption = idx != -1 ? g_ mapTypesText[idx] : "";599 let idx = g_MapTypes.indexOf(g_GameList[g].mapType); 600 Engine.GetGUIObjectByName("sgMapType").caption = idx != -1 ? g_MapTypesText[idx] : ""; 601 601 602 602 // Display map description if it exists, otherwise display a placeholder. 603 603 if (mapData && mapData.settings.Description) 604 604 var mapDescription = translate(mapData.settings.Description); 605 605 else … … 629 629 630 630 // TODO: What about valid host names? 631 631 // Check if it looks like an ip address 632 632 if (sip.split('.').length != 4) 633 633 { 634 addChatMessage({ "from": "system", "text": sprintf(translate("This game's address '%(ip)s' does not appear to be valid."), { ip: sip }) });634 addChatMessage({ "from": "system", "text": sprintf(translate("This game's address '%(ip)s' does not appear to be valid."), { "ip": sip }) }); 635 635 return; 636 636 } 637 637 638 638 // Open Multiplayer connection window with join option. 639 Engine.PushGuiPage("page_gamesetup_mp.xml", { multiplayerGameType: "join", name: sname, ip: sip, rating: g_userRating });639 Engine.PushGuiPage("page_gamesetup_mp.xml", { "multiplayerGameType": "join", "name": sname, "ip": sip, "rating": g_UserRating }); 640 640 } 641 641 } 642 642 643 643 /** 644 644 * Start the hosting process. 645 645 */ 646 646 function hostGame() 647 647 { 648 648 // Open Multiplayer connection window with host option. 649 Engine.PushGuiPage("page_gamesetup_mp.xml", { multiplayerGameType: "host", name: g_Name, rating: g_userRating });649 Engine.PushGuiPage("page_gamesetup_mp.xml", { "multiplayerGameType": "host", "name": g_Name, "rating": g_UserRating }); 650 650 } 651 651 652 652 //////////////////////////////////////////////////////////////////////////////////////////////// 653 653 // Utils 654 654 //////////////////////////////////////////////////////////////////////////////////////////////// … … 700 700 var [name, status, rating] = formatPlayerListEntry(nick, presence, "-"); 701 701 playerList.push(name); 702 702 presenceList.push(status); 703 703 nickList.push(nick); 704 704 ratingList.push(String(rating)); 705 addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { nick: nick }), "key": g_specialKey });705 addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { "nick": nick }), "key": g_SpecialKey }); 706 706 break; 707 707 case "leave": 708 708 if (nickIndex == -1) // Left, but not present (TODO: warn about this?) 709 709 break; 710 710 playerList.splice(nickIndex, 1); 711 711 presenceList.splice(nickIndex, 1); 712 712 nickList.splice(nickIndex, 1); 713 713 ratingList.splice(nickIndex, 1); 714 addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { nick: nick }), "key": g_specialKey });714 addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { "nick": nick }), "key": g_SpecialKey }); 715 715 break; 716 716 case "nick": 717 717 if (nickIndex == -1) // Changed nick, but not present (shouldn't ever happen) 718 718 break; 719 719 if (!isValidNick(message.data)) 720 720 { 721 addChatMessage({ "from": "system", "text": sprintf(translate("Invalid nickname: %(nick)s"), { nick: message.data })});721 addChatMessage({ "from": "system", "text": sprintf(translate("Invalid nickname: %(nick)s"), { "nick": message.data }) }); 722 722 break; 723 723 } 724 724 var [name, status, rating] = formatPlayerListEntry(message.data, presence, stripColorCodes(ratingList[nickIndex])); // TODO: actually we don't want to change the presence here, so use what was used before 725 725 playerList[nickIndex] = name; 726 726 // presence stays the same 727 727 nickList[nickIndex] = message.data; 728 addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { oldnick: nick, newnick: message.data }), "key": g_specialKey });728 addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { "oldnick": nick, "newnick": message.data }), "key": g_SpecialKey }); 729 729 break; 730 730 case "presence": 731 731 if (nickIndex == -1) // Changed presence, but not online (shouldn't ever happen) 732 732 break; 733 733 var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex])); … … 737 737 break; 738 738 case "subject": 739 739 updateSubject(message.text); 740 740 break; 741 741 default: 742 warn(sprintf("Unknown message.level '%(msglvl)s'", { msglvl: message.level }));742 warn(sprintf("Unknown message.level '%(msglvl)s'", { "msglvl": message.level })); 743 743 break; 744 744 } 745 745 // Push new data to GUI 746 746 playersBox.list_name = playerList; 747 747 playersBox.list_status = presenceList; 748 748 playersBox.list_rating = ratingList; 749 playersBox.list = nickList; 749 playersBox.list = nickList; 750 750 if (playersBox.selected >= playersBox.list.length) 751 751 playersBox.selected = -1; 752 752 break; 753 753 case "system": 754 754 switch (message.level) … … 790 790 } 791 791 break; 792 792 } 793 793 break; 794 794 default: 795 error(sprintf("Unrecognised message type %(msgtype)s", { msgtype: message.type }));795 error(sprintf("Unrecognised message type %(msgtype)s", { "msgtype": message.type })); 796 796 } 797 797 } 798 798 } 799 799 800 /* Messages */801 800 function submitChatInput() 802 801 { 803 802 var input = Engine.GetGUIObjectByName("chatInput"); 804 803 var text = input.caption; 805 804 if (text.length) … … 850 849 break; 851 850 case "say": 852 851 case "me": 853 852 return false; 854 853 default: 855 addChatMessage({ "from":"system", "text": sprintf(translate("We're sorry, the '%(cmd)s' command is not supported."), { cmd: cmd})});854 addChatMessage({ "from":"system", "text": sprintf(translate("We're sorry, the '%(cmd)s' command is not supported."), { "cmd": cmd }) }); 856 855 } 857 856 return true; 858 857 } 859 858 860 859 /** … … 868 867 if (msg.from) 869 868 { 870 869 // Display the moderator symbol in the chatbox. 871 870 var playerRole = Engine.LobbyGetPlayerRole(msg.from); 872 871 if (playerRole == "moderator") 873 msg.from = g_ modPrefix + msg.from;872 msg.from = g_ModPrefix + msg.from; 874 873 } 875 874 else 876 875 msg.from = null; 877 876 if (!msg.color) 878 877 msg.color = null; … … 934 933 var [command, message] = ircSplit(text); 935 934 switch (command) 936 935 { 937 936 case "me": 938 937 // Translation: IRC message prefix when the sender uses the /me command. 939 var senderString = '[font="sans-bold-13"]' + sprintf(translate("* %(sender)s"), { sender: coloredFrom }) + '[/font]';938 var senderString = '[font="sans-bold-13"]' + sprintf(translate("* %(sender)s"), { "sender": coloredFrom }) + '[/font]'; 940 939 // Translation: IRC message issued using the ‘/me’ command. 941 var formattedMessage = sprintf(translate("%(sender)s %(action)s"), { sender: senderString, action: message });940 var formattedMessage = sprintf(translate("%(sender)s %(action)s"), { "sender": senderString, "action": message }); 942 941 break; 943 942 case "say": 944 943 // Translation: IRC message prefix. 945 var senderString = '[font="sans-bold-13"]' + sprintf(translate("<%(sender)s>"), { sender: coloredFrom }) + '[/font]';944 var senderString = '[font="sans-bold-13"]' + sprintf(translate("<%(sender)s>"), { "sender": coloredFrom }) + '[/font]'; 946 945 // Translation: IRC message. 947 var formattedMessage = sprintf(translate("%(sender)s %(message)s"), { sender: senderString, message: message });946 var formattedMessage = sprintf(translate("%(sender)s %(message)s"), { "sender": senderString, "message": message }); 948 947 break 949 948 case "special": 950 if (key === g_ specialKey)949 if (key === g_SpecialKey) 951 950 // Translation: IRC system message. 952 var formattedMessage = '[font="sans-bold-13"]' + sprintf(translate("== %(message)s"), { message: message }) + '[/font]';951 var formattedMessage = '[font="sans-bold-13"]' + sprintf(translate("== %(message)s"), { "message": message }) + '[/font]'; 953 952 else 954 953 { 955 954 // Translation: IRC message prefix. 956 var senderString = '[font="sans-bold-13"]' + sprintf(translate("<%(sender)s>"), { sender: coloredFrom }) + '[/font]';955 var senderString = '[font="sans-bold-13"]' + sprintf(translate("<%(sender)s>"), { "sender": coloredFrom }) + '[/font]'; 957 956 // Translation: IRC message. 958 var formattedMessage = sprintf(translate("%(sender)s %(message)s"), { sender: senderString, message: message });957 var formattedMessage = sprintf(translate("%(sender)s %(message)s"), { "sender": senderString, "message": message }); 959 958 } 960 959 break; 961 960 default: 962 961 // This should never happen. 963 962 var formattedMessage = ""; 964 963 } 965 964 } 966 965 else 967 966 { 968 967 // Translation: IRC message prefix. 969 var senderString = '[font="sans-bold-13"]' + sprintf(translate("<%(sender)s>"), { sender: coloredFrom }) + '[/font]';968 var senderString = '[font="sans-bold-13"]' + sprintf(translate("<%(sender)s>"), { "sender": coloredFrom }) + '[/font]'; 970 969 // Translation: IRC message. 971 var formattedMessage = sprintf(translate("%(sender)s %(message)s"), { sender: senderString, message: text });970 var formattedMessage = sprintf(translate("%(sender)s %(message)s"), { "sender": senderString, "message": text }); 972 971 } 973 972 974 973 // Build time header if enabled 975 if (g_ timestamp)974 if (g_ShowTimestamp) 976 975 { 977 976 978 977 var time; 979 978 if (datetime) 980 979 { … … 991 990 // For a list of symbols that you can use, see: 992 991 // https://sites.google.com/site/icuprojectuserguide/formatparse/datetime?pli=1#TOC-Date-Field-Symbol-Table 993 992 var timeString = Engine.FormatMillisecondsIntoDateString(time.getTime(), translate("HH:mm")); 994 993 995 994 // Translation: Time prefix as shown in the multiplayer lobby (when you enable it in the options page). 996 var timePrefixString = '[font="sans-bold-13"]' + sprintf(translate("\\[%(time)s]"), { time: timeString }) + '[/font]';995 var timePrefixString = '[font="sans-bold-13"]' + sprintf(translate("\\[%(time)s]"), { "time": timeString }) + '[/font]'; 997 996 998 997 // Translation: IRC message format when there is a time prefix. 999 return sprintf(translate("%(time)s %(message)s"), { time: timePrefixString, message: formattedMessage });998 return sprintf(translate("%(time)s %(message)s"), { "time": timePrefixString, "message": formattedMessage }); 1000 999 } 1001 1000 else 1002 1001 return formattedMessage; 1003 1002 } 1004 1003 … … 1011 1010 { 1012 1011 // Integer time in seconds. 1013 1012 var time = Math.floor(Date.now() / 1000); 1014 1013 1015 1014 // Update or initialize the user in the spam monitor. 1016 if (g_ spamMonitor[from])1017 g_ spamMonitor[from][0]++;1015 if (g_SpamMonitor[from]) 1016 g_SpamMonitor[from][0]++; 1018 1017 else 1019 g_ spamMonitor[from] = [1, time, 0];1018 g_SpamMonitor[from] = [1, time, 0]; 1020 1019 } 1021 1020 1022 1021 /** 1023 1022 * Check if a message is spam. 1024 1023 * … … 1030 1029 { 1031 1030 // Integer time in seconds. 1032 1031 var time = Math.floor(Date.now() / 1000); 1033 1032 1034 1033 // Initialize if not already in the database. 1035 if (!g_ spamMonitor[from])1036 g_ spamMonitor[from] = [1, time, 0];1034 if (!g_SpamMonitor[from]) 1035 g_SpamMonitor[from] = [1, time, 0]; 1037 1036 1038 1037 // Block blank lines. 1039 1038 if (text == " ") 1040 1039 return true; 1041 1040 // Block users who are still within their spam block period. 1042 else if (g_ spamMonitor[from][2] + SPAM_BLOCK_LENGTH>= time)1041 else if (g_SpamMonitor[from][2] + g_SpamBlockLength >= time) 1043 1042 return true; 1044 1043 // Block users who exceed the rate of 1 message per second for five seconds and are not already blocked. TODO: Make this smarter and block profanity. 1045 else if (g_ spamMonitor[from][0] == 6)1044 else if (g_SpamMonitor[from][0] == 6) 1046 1045 { 1047 g_ spamMonitor[from][2] = time;1046 g_SpamMonitor[from][2] = time; 1048 1047 if (from == g_Name) 1049 1048 addChatMessage({ "from": "system", "text": translate("Please do not spam. You have been blocked for thirty seconds.") }); 1050 1049 return true; 1051 1050 } 1052 1051 // Return false if everything is clear. … … 1061 1060 { 1062 1061 // Integer time in seconds. 1063 1062 var time = Math.floor(Date.now() / 1000); 1064 1063 1065 1064 // Clear message count every 5 seconds. 1066 for each (var stats in g_spamMonitor)1065 for (let i in g_SpamMonitor) 1067 1066 { 1068 if ( stats[1] + 5 <= time)1067 if (g_SpamMonitor[i][1] + 5 <= time) 1069 1068 { 1070 stats[1] = time;1071 stats[0] = 0;1069 g_SpamMonitor[i][1] = time; 1070 g_SpamMonitor[i][0] = 0; 1072 1071 } 1073 1072 } 1074 1075 1073 } 1076 1074 1077 1075 /* Utilities */ 1078 1076 // Generate a (mostly) unique color for this player based on their name. 1079 1077 // See http://stackoverflow.com/questions/3426404/create-a-hexadecimal-colour-based-on-a-string-with-jquery-javascript … … 1106 1104 if (color) { 1107 1105 color = color.split("."); 1108 1106 return ('[color="' + playername.split("").map(function (c, i) color.slice(i * 3, i * 3 + 3).join(" ") + '"]' + c + '[/color][color="') 1109 1107 .join("") + '"]').slice(0, -10); 1110 1108 } 1111 return '[color="' + getPlayerColor(playername.replace(g_ modPrefix, "")) + '"]' + playername + '[/color]';1109 return '[color="' + getPlayerColor(playername.replace(g_ModPrefix, "")) + '"]' + playername + '[/color]'; 1112 1110 } 1113 1111 1114 1112 // Ensure `value` is between 0 and 1. 1115 1113 function clampColorValue(value) 1116 1114 {