Changeset View
Standalone View
binaries/data/mods/public/gui/gamesetup/gamesetup.js
Show All 19 Lines | |||||
*/ | */ | ||||
const g_MapPath = { | const g_MapPath = { | ||||
"random": "maps/random/", | "random": "maps/random/", | ||||
"scenario": "maps/scenarios/", | "scenario": "maps/scenarios/", | ||||
"skirmish": "maps/skirmishes/" | "skirmish": "maps/skirmishes/" | ||||
}; | }; | ||||
/** | /** | ||||
* Containing the colors to highlight the ready status of players, | |||||
* the chat ready messages and | |||||
* the tooltips and captions for the ready button | |||||
*/ | |||||
const g_ReadyData = [ | |||||
{ | |||||
"color": "", | |||||
"chat": translate("* %(username)s is not ready."), | |||||
"caption": translate("I'm ready"), | |||||
"tooltip": translate("State that you are ready to play.") | |||||
}, | |||||
{ | |||||
"color": "green", | |||||
"chat": translate("* %(username)s is ready!"), | |||||
"caption": translate("Stay ready"), | |||||
"tooltip": translate("Stay ready even when the game settings change.") | |||||
}, | |||||
{ | |||||
"color": "blue", | |||||
elexis: That color is unacceptably ugly. Perhaps `150 150 250` | |||||
"caption": translate("I'm not ready!"), | |||||
elexisUnsubmitted Not Done Inline ActionsYou removed the check but didn't add the empty string here, sounds like breakage elexis: You removed the check but didn't add the empty string here, sounds like breakage | |||||
"tooltip": translate("State that you are not ready to play.") | |||||
} | |||||
]; | |||||
/** | |||||
* Processes a CNetMessage (see NetMessage.h, NetMessages.h) sent by the CNetServer. | * Processes a CNetMessage (see NetMessage.h, NetMessages.h) sent by the CNetServer. | ||||
*/ | */ | ||||
const g_NetMessageTypes = { | const g_NetMessageTypes = { | ||||
"netstatus": msg => handleNetStatusMessage(msg), | "netstatus": msg => handleNetStatusMessage(msg), | ||||
"netwarn": msg => addNetworkWarning(msg), | "netwarn": msg => addNetworkWarning(msg), | ||||
"gamesetup": msg => handleGamesetupMessage(msg), | "gamesetup": msg => handleGamesetupMessage(msg), | ||||
"players": msg => handlePlayerAssignmentMessage(msg), | "players": msg => handlePlayerAssignmentMessage(msg), | ||||
"ready": msg => handleReadyMessage(msg), | "ready": msg => handleReadyMessage(msg), | ||||
Show All 11 Lines | const g_FormatChatMessage = { | ||||
"connect": (msg, user) => systemMessage(sprintf(translate("%(username)s has joined"), { "username": user })), | "connect": (msg, user) => systemMessage(sprintf(translate("%(username)s has joined"), { "username": user })), | ||||
"disconnect": (msg, user) => systemMessage(sprintf(translate("%(username)s has left"), { "username": user })), | "disconnect": (msg, user) => systemMessage(sprintf(translate("%(username)s has left"), { "username": user })), | ||||
"kicked": (msg, user) => systemMessage(sprintf(translate("%(username)s has been kicked"), { "username": user })), | "kicked": (msg, user) => systemMessage(sprintf(translate("%(username)s has been kicked"), { "username": user })), | ||||
"banned": (msg, user) => systemMessage(sprintf(translate("%(username)s has been banned"), { "username": user })), | "banned": (msg, user) => systemMessage(sprintf(translate("%(username)s has been banned"), { "username": user })), | ||||
"chat": (msg, user) => sprintf(translate("%(username)s %(message)s"), { | "chat": (msg, user) => sprintf(translate("%(username)s %(message)s"), { | ||||
"username": senderFont(sprintf(translate("<%(username)s>"), { "username": user })), | "username": senderFont(sprintf(translate("<%(username)s>"), { "username": user })), | ||||
"message": escapeText(msg.text || "") | "message": escapeText(msg.text || "") | ||||
}), | }), | ||||
"ready": (msg, user) => sprintf(translate("* %(username)s is ready!"), { | "ready": (msg, user) => g_ReadyData[msg.status] && sprintf(g_ReadyData[msg.status].chat, { "username": user }), | ||||
Not Done Inline ActionsThe first check seems okay, if the intention is to mute errors sent by a trollhost. But in that case the g_PlayerAssignments[guid].status].color should also have a check. If we don't care about trollhosts, then this check can be removed. I'd prefer to remove the second check and add an empty string to the global array, so it's more obvious that nothing will be printed in that case and that the array always has all properties. elexis: The first check seems okay, if the intention is to mute errors sent by a trollhost. But in that… | |||||
Not Done Inline ActionsFirst check should still be removed as the patch doesn't care about trollhosts otherwise elexis: First check should still be removed as the patch doesn't care about trollhosts otherwise | |||||
"username": user | |||||
}), | |||||
"not-ready": (msg, user) => sprintf(translate("* %(username)s is not ready."), { | |||||
"username": user | |||||
}), | |||||
"clientlist": (msg, user) => getUsernameList() | "clientlist": (msg, user) => getUsernameList() | ||||
}; | }; | ||||
/** | /** | ||||
* The dropdownlist items will appear in the order they are added. | * The dropdownlist items will appear in the order they are added. | ||||
*/ | */ | ||||
const g_MapFilters = [ | const g_MapFilters = [ | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
const g_UnassignedColor = "140 140 140"; | const g_UnassignedColor = "140 140 140"; | ||||
/** | /** | ||||
* Highlight observer players in the dropdownlist. | * Highlight observer players in the dropdownlist. | ||||
*/ | */ | ||||
const g_UnassignedPlayerColor = "170 170 250"; | const g_UnassignedPlayerColor = "170 170 250"; | ||||
/** | /** | ||||
* Highlight ready players. | |||||
*/ | |||||
const g_ReadyColor = "green"; | |||||
/** | |||||
* Placeholder item for the map-dropdownlist. | * Placeholder item for the map-dropdownlist. | ||||
*/ | */ | ||||
Not Done Inline Actions(would move the "and" to the line above, since that's also the place where the comma would be placed) elexis: (would move the "and" to the line above, since that's also the place where the comma would be… | |||||
const g_RandomMap = '[color="' + g_ColorRandom + '"]' + translateWithContext("map selection", "Random") + "[/color]"; | const g_RandomMap = '[color="' + g_ColorRandom + '"]' + translateWithContext("map selection", "Random") + "[/color]"; | ||||
/** | /** | ||||
Not Done Inline ActionsBetter move it above g_FormatChatMessage, so that it's defined before being refered to (though only a code style thing, since the format chat functions won't be executed before the ready data is defined) elexis: Better move it above `g_FormatChatMessage`, so that it's defined before being refered to… | |||||
* Placeholder item for the civ-dropdownlists. | * Placeholder item for the civ-dropdownlists. | ||||
*/ | */ | ||||
const g_RandomCiv = '[color="' + g_ColorRandom + '"]' + translateWithContext("civilization", "Random") + '[/color]'; | const g_RandomCiv = '[color="' + g_ColorRandom + '"]' + translateWithContext("civilization", "Random") + '[/color]'; | ||||
/** | /** | ||||
Not Done Inline Actions! -> . elexis: ! -> .
Perhaps it should also or instead state that the player accepts the settings.
| |||||
* Whether this is a single- or multiplayer match. | * Whether this is a single- or multiplayer match. | ||||
Not Done Inline Actions\n after the comma elexis: \n after the comma
| |||||
*/ | */ | ||||
var g_IsNetworked; | var g_IsNetworked; | ||||
/** | /** | ||||
Not Done Inline ActionsStay ready comma elexis: Stay ready comma | |||||
Not Done Inline Actionssure? Imarok: sure? | |||||
Not Done Inline ActionsNo, but it appears to be a https://en.wikipedia.org/wiki/Conjunction_(grammar)#Subordinating_conjunctions elexis: No, but it appears to be a https://en.wikipedia.org/wiki/Conjunction_… | |||||
Not Done Inline Actionsyeah and between main clause and subordinate clause comes no comma. Imarok: yeah and between main clause and subordinate clause comes no comma. | |||||
Not Done Inline Actionsthanks for looking it up :) elexis: thanks for looking it up :) | |||||
* Is this user in control of game settings (i.e. singleplayer or host of a multiplayergame). | * Is this user in control of game settings (i.e. singleplayer or host of a multiplayergame). | ||||
*/ | */ | ||||
var g_IsController; | var g_IsController; | ||||
/** | /** | ||||
Not Done Inline Actions\n after } elexis: \n after } | |||||
* To report the game to the lobby bot. | * To report the game to the lobby bot. | ||||
*/ | */ | ||||
var g_ServerName; | var g_ServerName; | ||||
var g_ServerPort; | var g_ServerPort; | ||||
/** | /** | ||||
* States whether the GUI is currently updated in response to network messages instead of user input | * States whether the GUI is currently updated in response to network messages instead of user input | ||||
* and therefore shouldn't send further messages to the network. | * and therefore shouldn't send further messages to the network. | ||||
*/ | */ | ||||
var g_IsInGuiUpdate; | var g_IsInGuiUpdate; | ||||
/** | /** | ||||
* Whether the current player is ready to start the game. | * Whether the current player is ready to start the game. | ||||
* 0 - not ready | |||||
* 1 - ready | |||||
* 2 - stay ready | |||||
*/ | */ | ||||
var g_IsReady; | var g_IsReady; | ||||
/** | /** | ||||
* Ignore duplicate ready commands on init. | * Ignore duplicate ready commands on init. | ||||
*/ | */ | ||||
var g_ReadyInit = true; | var g_ReadyInit = true; | ||||
▲ Show 20 Lines • Show All 518 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Called whenever a client clicks on ready (or not ready). | * Called whenever a client clicks on ready (or not ready). | ||||
* @param {Object} message | * @param {Object} message | ||||
*/ | */ | ||||
function handleReadyMessage(message) | function handleReadyMessage(message) | ||||
{ | { | ||||
--g_ReadyChanged; | --g_ReadyChanged; | ||||
if (g_ReadyChanged < 1 && g_PlayerAssignments[message.guid].player != -1) | if (g_ReadyChanged < 1 && g_PlayerAssignments[message.guid].player != -1 && message.status < 2) | ||||
Done Inline ActionsIt were preferable to not hardcode the design decision to not display changes to stay-ready here. Improvement: Stay-Ready chat message, can be done in a separate simple ticket. However if we display a stay-ready chatmessage, then we will get one more chat message if people doubeclick (which might occur often). elexis: It were preferable to not hardcode the design decision to not display changes to stay-ready… | |||||
Not Done Inline ActionsThe < 2 check is unneeded, right? as that function will return an empty string and that wont print anything elexis: The < 2 check is unneeded, right? as that function will return an empty string and that wont… | |||||
addChatMessage({ | addChatMessage({ | ||||
"type": message.status == 1 ? "ready" : "not-ready", | "type": "ready", | ||||
"status": message.status, | |||||
Done Inline ActionsThis g_FormatChatMessage could just be "ready", the status could be passed as an argument and the translated strings could be moved to the proposed array below. When not implementing the timer proposed above, g_FormatChatMessage can return an empty string for the stay-ready case for now to still remove both hardcodings. elexis: This `g_FormatChatMessage` could just be "ready", the status could be passed as an argument and… | |||||
"guid": message.guid | "guid": message.guid | ||||
}); | }); | ||||
if (!g_IsController) | if (!g_IsController) | ||||
return; | return; | ||||
g_PlayerAssignments[message.guid].status = +message.status == 1; | g_PlayerAssignments[message.guid].status = +message.status == 1; | ||||
updateReadyUI(); | updateReadyUI(); | ||||
▲ Show 20 Lines • Show All 1,095 Lines • ▼ Show 20 Lines | if (msg.type == "chat") | ||||
if (userName != g_PlayerAssignments[msg.guid].name) | if (userName != g_PlayerAssignments[msg.guid].name) | ||||
notifyUser(userName, msg.text); | notifyUser(userName, msg.text); | ||||
} | } | ||||
let user = colorizePlayernameByGUID(msg.guid || -1, msg.username || ""); | let user = colorizePlayernameByGUID(msg.guid || -1, msg.username || ""); | ||||
let text = g_FormatChatMessage[msg.type](msg, user); | let text = g_FormatChatMessage[msg.type](msg, user); | ||||
if (!text) | |||||
return; | |||||
if (Engine.ConfigDB_GetValue("user", "chat.timestamp") == "true") | if (Engine.ConfigDB_GetValue("user", "chat.timestamp") == "true") | ||||
text = sprintf(translate("%(time)s %(message)s"), { | text = sprintf(translate("%(time)s %(message)s"), { | ||||
"time": sprintf(translate("\\[%(time)s]"), { | "time": sprintf(translate("\\[%(time)s]"), { | ||||
"time": Engine.FormatMillisecondsIntoDateStringLocal(new Date().getTime(), translate("HH:mm")) | "time": Engine.FormatMillisecondsIntoDateStringLocal(new Date().getTime(), translate("HH:mm")) | ||||
}), | }), | ||||
"message": text | "message": text | ||||
}); | }); | ||||
Show All 21 Lines | function resetTeams() | ||||
for (let i in g_GameAttributes.settings.PlayerData) | for (let i in g_GameAttributes.settings.PlayerData) | ||||
g_GameAttributes.settings.PlayerData[i].Team = -1; | g_GameAttributes.settings.PlayerData[i].Team = -1; | ||||
updateGameAttributes(); | updateGameAttributes(); | ||||
} | } | ||||
function toggleReady() | function toggleReady() | ||||
{ | { | ||||
setReady(!g_IsReady); | setReady((g_IsReady + 1) % 3); | ||||
Done Inline ActionsI guess the only reason we have that function is to not add a global ref to the XML file. elexis: I guess the only reason we have that function is to not add a global ref to the XML file. | |||||
Not Done Inline Actionsprobably Imarok: probably | |||||
} | } | ||||
function setReady(ready, sendMessage = true) | function setReady(ready, sendMessage = true) | ||||
{ | { | ||||
g_IsReady = ready; | g_IsReady = ready; | ||||
if (sendMessage) | if (sendMessage) | ||||
Engine.SendNetworkReady(+g_IsReady); | Engine.SendNetworkReady(+g_IsReady); | ||||
if (g_IsController) | if (g_IsController) | ||||
return; | return; | ||||
let button = Engine.GetGUIObjectByName("startGame"); | let button = Engine.GetGUIObjectByName("startGame"); | ||||
button.caption = g_ReadyData[+g_IsReady].caption; | |||||
button.caption = g_IsReady ? | button.tooltip = g_ReadyData[+g_IsReady].tooltip; | ||||
Done Inline ActionsWe don't construct these constant arrays again and again but init them only once. It could become a global array with 3 elements, each being an object with caption and tooltip. While at it move the colors there as well. elexis: We don't construct these constant arrays again and again but init them only once. It could… | |||||
translate("I'm not ready!") : | |||||
translate("I'm ready"); | |||||
button.tooltip = g_IsReady ? | |||||
translate("State that you are not ready to play.") : | |||||
translate("State that you are ready to play!"); | |||||
} | } | ||||
function updateReadyUI() | function updateReadyUI() | ||||
{ | { | ||||
if (!g_IsNetworked) | if (!g_IsNetworked) | ||||
return; | return; | ||||
let isAI = new Array(g_MaxPlayers + 1).fill(true); | let isAI = new Array(g_MaxPlayers + 1).fill(true); | ||||
let allReady = true; | let allReady = true; | ||||
for (let guid in g_PlayerAssignments) | for (let guid in g_PlayerAssignments) | ||||
{ | { | ||||
// We don't really care whether observers are ready. | // We don't really care whether observers are ready. | ||||
if (g_PlayerAssignments[guid].player == -1 || !g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1]) | if (g_PlayerAssignments[guid].player == -1 || !g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1]) | ||||
continue; | continue; | ||||
let pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1] : {}; | let pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1] : {}; | ||||
let pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[g_PlayerAssignments[guid].player - 1] : {}; | let pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[g_PlayerAssignments[guid].player - 1] : {}; | ||||
isAI[g_PlayerAssignments[guid].player] = false; | isAI[g_PlayerAssignments[guid].player] = false; | ||||
if (g_PlayerAssignments[guid].status || !g_IsNetworked) | if (g_PlayerAssignments[guid].status) | ||||
Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = '[color="' + g_ReadyColor + '"]' + translate(getSetting(pData, pDefs, "Name")) + '[/color]'; | Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = | ||||
Not Done Inline ActionsTrailing space elexis: Trailing space | |||||
'[color="' + g_ReadyData[+g_PlayerAssignments[guid].status].color + '"]' + | |||||
translate(getSetting(pData, pDefs, "Name")) + '[/color]'; | |||||
else | else | ||||
{ | { | ||||
Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = translate(getSetting(pData, pDefs, "Name")); | Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = translate(getSetting(pData, pDefs, "Name")); | ||||
allReady = false; | allReady = false; | ||||
} | } | ||||
} | } | ||||
// AIs are always ready. | // AIs are always ready. | ||||
for (let playerid = 0; playerid < g_MaxPlayers; ++playerid) | for (let playerid = 0; playerid < g_MaxPlayers; ++playerid) | ||||
{ | { | ||||
if (!g_GameAttributes.settings.PlayerData[playerid]) | if (!g_GameAttributes.settings.PlayerData[playerid]) | ||||
continue; | continue; | ||||
let pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[playerid] : {}; | let pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[playerid] : {}; | ||||
let pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[playerid] : {}; | let pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[playerid] : {}; | ||||
if (isAI[playerid + 1]) | if (isAI[playerid + 1]) | ||||
Engine.GetGUIObjectByName("playerName[" + playerid + "]").caption = '[color="' + g_ReadyColor + '"]' + translate(getSetting(pData, pDefs, "Name")) + '[/color]'; | Engine.GetGUIObjectByName("playerName[" + playerid + "]").caption = | ||||
'[color="' + g_ReadyData[2].color + '"]' + translate(getSetting(pData, pDefs, "Name")) + '[/color]'; | |||||
} | } | ||||
// The host is not allowed to start until everyone is ready. | // The host is not allowed to start until everyone is ready. | ||||
if (g_IsNetworked && g_IsController) | if (g_IsNetworked && g_IsController) | ||||
{ | { | ||||
let startGameButton = Engine.GetGUIObjectByName("startGame"); | let startGameButton = Engine.GetGUIObjectByName("startGame"); | ||||
startGameButton.enabled = allReady; | startGameButton.enabled = allReady; | ||||
// Add a explanation on to the tooltip if disabled. | // Add a explanation on to the tooltip if disabled. | ||||
Show All 20 Lines | function resetReadyData() | ||||
g_ReadyChanged = 2; | g_ReadyChanged = 2; | ||||
if (!g_IsNetworked) | if (!g_IsNetworked) | ||||
g_IsReady = true; | g_IsReady = true; | ||||
else if (g_IsController) | else if (g_IsController) | ||||
{ | { | ||||
Engine.ClearAllPlayerReady(); | Engine.ClearAllPlayerReady(); | ||||
setReady(true); | setReady(true); | ||||
} | } | ||||
else | else if (g_IsReady != 2) | ||||
setReady(false, false); | setReady(false, false); | ||||
} | } | ||||
/** | /** | ||||
* Send a list of playernames and distinct between players and observers. | * Send a list of playernames and distinct between players and observers. | ||||
* Don't send teams, AIs or anything else until the game was started. | * Don't send teams, AIs or anything else until the game was started. | ||||
* The playerData format from g_GameAttributes is kept to reuse the GUI function presenting the data. | * The playerData format from g_GameAttributes is kept to reuse the GUI function presenting the data. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 58 Lines • Show Last 20 Lines |
That color is unacceptably ugly. Perhaps 150 150 250