Ticket #2640: 2640_2.patch

File 2640_2.patch, 26.6 KB (added by Matt Doerksen, 9 years ago)

Move in-game chat functionality to functions_chat.js for aggregation.

  • new file inaries/data/mods/public/gui/common/functions_chat.js

    From 2e3cfb8492fd8a5a84bdf8f12a235c9e3eca569b Mon Sep 17 00:00:00 2001
    From: matt <matthewdoerksen@hotmail.com>
    Date: Thu, 18 Jun 2015 21:57:48 -0700
    Subject: [PATCH] Move in-game chat functionality to functions_chat.js for
     aggregation.
    
    ---
     .../data/mods/public/gui/common/functions_chat.js  | 266 +++++++++++++++++++++
     .../data/mods/public/gui/gamesetup/gamesetup.js    |  79 +-----
     .../data/mods/public/gui/gamesetup/gamesetup.xml   |   1 +
     binaries/data/mods/public/gui/session/messages.js  | 223 +----------------
     binaries/data/mods/public/gui/session/session.xml  |   1 +
     5 files changed, 286 insertions(+), 284 deletions(-)
     create mode 100644 binaries/data/mods/public/gui/common/functions_chat.js
    
    diff --git a/binaries/data/mods/public/gui/common/functions_chat.js b/binaries/data/mods/public/gui/common/functions_chat.js
    new file mode 100644
    index 0000000..b08f5e2
    - +  
     1function addChatMessageGameSetup(msg)
     2{
     3    var username = "";
     4    if (msg.username)
     5        username = escapeText(msg.username);
     6    else if (msg.guid && g_PlayerAssignments[msg.guid])
     7        username = escapeText(g_PlayerAssignments[msg.guid].name);
     8
     9    var message = "";
     10    if ("text" in msg && msg.text)
     11        message = escapeText(msg.text);
     12
     13    // TODO: Maybe host should have distinct font/color?
     14    var color = "white";
     15
     16    if (msg.guid && g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
     17    {
     18        // Valid player who has been assigned - get player color
     19        var player = g_PlayerAssignments[msg.guid].player - 1;
     20        var mapName = g_GameAttributes.map;
     21        var mapData = loadMapData(mapName);
     22        var mapSettings = (mapData && mapData.settings ? mapData.settings : {});
     23        var pData = mapSettings.PlayerData ? mapSettings.PlayerData[player] : {};
     24        var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[player] : {};
     25
     26        color = rgbToGuiColor(getSetting(pData, pDefs, "Color"));
     27    }
     28
     29    var formatted;
     30    switch (msg.type)
     31    {
     32    case "connect":
     33        var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
     34        formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { message: sprintf(translate("%(username)s has joined"), { username: formattedUsername }) }) + '[/font]';
     35        break;
     36
     37    case "disconnect":
     38        var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
     39        formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { message: sprintf(translate("%(username)s has left"), { username: formattedUsername }) }) + '[/font]';
     40        break;
     41
     42    case "message":
     43        var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
     44        var formattedUsernamePrefix = '[font="sans-bold-13"]' + sprintf(translate("<%(username)s>"), { username: formattedUsername }) + '[/font]'
     45        formatted = sprintf(translate("%(username)s %(message)s"), { username: formattedUsernamePrefix, message: message });
     46        break;
     47
     48    case "ready":
     49        var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
     50        if (msg.ready)
     51            formatted = ' ' + sprintf(translate("* %(username)s is ready!"), { username: formattedUsername });
     52        else
     53            formatted = ' ' + sprintf(translate("* %(username)s is not ready."), { username: formattedUsername });
     54        break;
     55
     56    case "settings":
     57        formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { message: translate('Game settings have been changed') }) + '[/font]';
     58        break;
     59
     60    default:
     61        error(sprintf("Invalid chat message '%(message)s'", { message: uneval(msg) }));
     62        return;
     63    }
     64
     65    g_ChatMessages.push(formatted);
     66
     67    Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
     68}
     69
     70function addChatMessageSession(msg, playerAssignments)
     71{
     72    // Default to global assignments, but allow overriding for when reporting
     73    // new players joining
     74    if (!playerAssignments)
     75        playerAssignments = g_PlayerAssignments;
     76
     77    var playerColor, username;
     78
     79    // No context by default. May be set by parseChatCommands().
     80    msg.context = "";
     81
     82    if ("guid" in msg && playerAssignments[msg.guid])
     83    {
     84        var n = playerAssignments[msg.guid].player;
     85        // Observers have an ID of -1 which is not a valid index.
     86        if (n < 0)
     87            n = 0;
     88        playerColor = g_Players[n].color.r + " " + g_Players[n].color.g + " " + g_Players[n].color.b;
     89        username = escapeText(playerAssignments[msg.guid].name);
     90
     91        // Parse in-line commands in regular messages.
     92        if (msg.type == "message")
     93            parseChatCommands(msg, playerAssignments);
     94    }
     95    else if (msg.type == "defeat" && msg.player)
     96    {
     97        [username, playerColor] = getUsernameAndColor(msg.player);
     98    }
     99    else if (msg.type == "message")
     100    {
     101        [username, playerColor] = getUsernameAndColor(msg.player);
     102        parseChatCommands(msg, playerAssignments);
     103    }
     104    else
     105    {
     106        playerColor = "255 255 255";
     107        username = translate("Unknown player");
     108    }
     109
     110    var formatted;
     111
     112    switch (msg.type)
     113    {
     114    case "connect":
     115        formatted = sprintf(translate("%(player)s is starting to rejoin the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     116        break;
     117    case "disconnect":
     118        formatted = sprintf(translate("%(player)s has left the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     119        break;
     120    case "rejoined":
     121        formatted = sprintf(translate("%(player)s has rejoined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     122        break;
     123    case "defeat":
     124        // In singleplayer, the local player is "You". "You has" is incorrect.
     125        if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
     126            formatted = translate("You have been defeated.");
     127        else
     128            formatted = sprintf(translate("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     129        break;
     130    case "diplomacy":
     131        var message;
     132        if (msg.player == Engine.GetPlayerID())
     133        {
     134            [username, playerColor] = getUsernameAndColor(msg.player1);
     135            if (msg.status == "ally")
     136                message = translate("You are now allied with %(player)s.");
     137            else if (msg.status == "enemy")
     138                message = translate("You are now at war with %(player)s.");
     139            else // (msg.status == "neutral")
     140                message = translate("You are now neutral with %(player)s.");
     141        }
     142        else if (msg.player1 == Engine.GetPlayerID())
     143        {
     144            [username, playerColor] = getUsernameAndColor(msg.player);
     145            if (msg.status == "ally")
     146                message = translate("%(player)s is now allied with you.");
     147            else if (msg.status == "enemy")
     148                message = translate("%(player)s is now at war with you.");
     149            else // (msg.status == "neutral")
     150                message = translate("%(player)s is now neutral with you.");
     151        }
     152        else // No need for other players to know of this.
     153            return;
     154
     155        formatted = sprintf(message, { "player": '[color="'+ playerColor + '"]' + username + '[/color]' });
     156        break;
     157    case "tribute":
     158        if (msg.player != Engine.GetPlayerID())
     159            return;
     160
     161        [username, playerColor] = getUsernameAndColor(msg.player1);
     162
     163        // Format the amounts to proper English: 200 food, 100 wood, and 300 metal; 100 food; 400 wood and 200 stone
     164        let amounts = Object.keys(msg.amounts)
     165            .filter(function (type) { return msg.amounts[type] > 0; })
     166            .map(function (type) { return sprintf(translate("%(amount)s %(resourceType)s"), {
     167                "amount": msg.amounts[type],
     168                "resourceType": getLocalizedResourceName(type, "withinSentence")});
     169            });
     170
     171        if (amounts.length > 1)
     172        {
     173            let lastAmount = amounts.pop();
     174            amounts = sprintf(translate("%(previousAmounts)s and %(lastAmount)s"), {
     175                previousAmounts: amounts.join(translate(", ")),
     176                lastAmount: lastAmount
     177            });
     178        }
     179
     180        formatted = sprintf(translate("%(player)s has sent you %(amounts)s."), {
     181            player: "[color=\"" + playerColor + "\"]" + username + "[/color]",
     182            amounts: amounts
     183        });
     184        break;
     185    case "attack":
     186        if (msg.player != Engine.GetPlayerID())
     187            return;
     188
     189        [username, playerColor] = getUsernameAndColor(msg.attacker);
     190        // Since livestock can be attacked/gathered by other players,
     191        // we display a more specific notification in this case to not confuse the player
     192        if (msg.targetIsDomesticAnimal)
     193            var message = translate("Your livestock have been attacked by %(attacker)s!");
     194        else
     195            var message = translate("You have been attacked by %(attacker)s!");
     196        formatted = sprintf(message, { attacker: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
     197        break;
     198    case "message":
     199        // May have been hidden by the 'team' command.
     200        if (msg.hide)
     201            return;
     202
     203        var message;
     204        if ("translate" in msg && msg.translate)
     205        {
     206            message = translate(msg.text); // No need to escape, not a user message.
     207            if ("translateParameters" in msg && msg.translateParameters)
     208            {
     209                var parameters = msg.parameters || {};
     210                translateObjectKeys(parameters, msg.translateParameters);
     211                message = sprintf(message, parameters);
     212            }
     213        }
     214        else
     215            message = escapeText(msg.text);
     216
     217        if (msg.action)
     218        {
     219            if (msg.context !== "")
     220            {
     221                formatted = sprintf(translate("(%(context)s) * %(user)s %(message)s"), {
     222                    context: msg.context,
     223                    user: "[color=\"" + playerColor + "\"]" + username + "[/color]",
     224                    message: message
     225                });
     226            }
     227            else
     228            {
     229                formatted = sprintf(translate("* %(user)s %(message)s"), {
     230                    user: "[color=\"" + playerColor + "\"]" + username + "[/color]",
     231                    message: message
     232                });
     233            }
     234        }
     235        else
     236        {
     237            var userTag = sprintf(translate("<%(user)s>"), { user: username })
     238            var formattedUserTag = sprintf(translate("<%(user)s>"), { user: "[color=\"" + playerColor + "\"]" + username + "[/color]" })
     239            if (msg.context !== "")
     240            {
     241                formatted = sprintf(translate("(%(context)s) %(userTag)s %(message)s"), {
     242                    context: msg.context,
     243                    userTag: formattedUserTag,
     244                    message: message
     245                });
     246            }
     247            else
     248            {
     249                formatted = sprintf(translate("%(userTag)s %(message)s"), { userTag: formattedUserTag, message: message});
     250            }
     251        }
     252        break;
     253    default:
     254        error(sprintf("Invalid chat message '%(message)s'", { message: uneval(msg) }));
     255        return;
     256    }
     257
     258    chatMessages.push(formatted);
     259    chatTimers.push(setTimeout(removeOldChatMessages, CHAT_TIMEOUT));
     260
     261    if (chatMessages.length > MAX_NUM_CHAT_LINES)
     262        removeOldChatMessages();
     263    else
     264        Engine.GetGUIObjectByName("chatText").caption = chatMessages.join("\n");
     265}
     266
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

    diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.js b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
    index 856b79d..960393a 100644
    a b function handleNetMessage(message)  
    451451                // If we have extra player slots and we are the controller, give the player an ID.
    452452                if (g_IsController && message.hosts[host].player === -1 && g_AssignedCount < g_GameAttributes.settings.PlayerData.length)
    453453                    Engine.AssignNetworkPlayer(g_AssignedCount + 1, host);
    454                 addChatMessage({ "type": "connect", "username": message.hosts[host].name });
     454                addChatMessageGameSetup({ "type": "connect", "username": message.hosts[host].name });
    455455                newPlayer = host;
    456456            }
    457457        }
    function handleNetMessage(message)  
    460460        {
    461461            if (!message.hosts[host])
    462462            {
    463                 addChatMessage({ "type": "disconnect", "guid": host });
     463                addChatMessageGameSetup({ "type": "disconnect", "guid": host });
    464464                if (g_PlayerAssignments[host].player != -1)
    465465                    resetReady = true; // Observers shouldn't reset ready.
    466466            }
    function handleNetMessage(message)  
    494494        break;
    495495
    496496    case "chat":
    497         addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
     497        addChatMessageGameSetup({ "type": "message", "guid": message.guid, "text": message.text });
    498498        break;
    499499
    500500    // Singular client to host message
    501501    case "ready":
    502502        g_ReadyChanged -= 1;
    503503        if (g_ReadyChanged < 1 && g_PlayerAssignments[message.guid].player != -1)
    504             addChatMessage({ "type": "ready", "guid": message.guid, "ready": +message.status == 1 });
     504            addChatMessageGameSetup({ "type": "ready", "guid": message.guid, "ready": +message.status == 1 });
    505505        if (!g_IsController)
    506506            break;
    507507        g_PlayerAssignments[message.guid].status = +message.status == 1;
    function submitChatInput()  
    16881688    }
    16891689}
    16901690
    1691 function addChatMessage(msg)
    1692 {
    1693     var username = "";
    1694     if (msg.username)
    1695         username = escapeText(msg.username);
    1696     else if (msg.guid && g_PlayerAssignments[msg.guid])
    1697         username = escapeText(g_PlayerAssignments[msg.guid].name);
    1698 
    1699     var message = "";
    1700     if ("text" in msg && msg.text)
    1701         message = escapeText(msg.text);
    1702 
    1703     // TODO: Maybe host should have distinct font/color?
    1704     var color = "white";
    1705 
    1706     if (msg.guid && g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
    1707     {
    1708         // Valid player who has been assigned - get player color
    1709         var player = g_PlayerAssignments[msg.guid].player - 1;
    1710         var mapName = g_GameAttributes.map;
    1711         var mapData = loadMapData(mapName);
    1712         var mapSettings = (mapData && mapData.settings ? mapData.settings : {});
    1713         var pData = mapSettings.PlayerData ? mapSettings.PlayerData[player] : {};
    1714         var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[player] : {};
    1715 
    1716         color = rgbToGuiColor(getSetting(pData, pDefs, "Color"));
    1717     }
    1718 
    1719     var formatted;
    1720     switch (msg.type)
    1721     {
    1722     case "connect":
    1723         var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
    1724         formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { message: sprintf(translate("%(username)s has joined"), { username: formattedUsername }) }) + '[/font]';
    1725         break;
    1726 
    1727     case "disconnect":
    1728         var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
    1729         formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { message: sprintf(translate("%(username)s has left"), { username: formattedUsername }) }) + '[/font]';
    1730         break;
    1731 
    1732     case "message":
    1733         var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
    1734         var formattedUsernamePrefix = '[font="sans-bold-13"]' + sprintf(translate("<%(username)s>"), { username: formattedUsername }) + '[/font]'
    1735         formatted = sprintf(translate("%(username)s %(message)s"), { username: formattedUsernamePrefix, message: message });
    1736         break;
    1737 
    1738     case "ready":
    1739         var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
    1740         if (msg.ready)
    1741             formatted = ' ' + sprintf(translate("* %(username)s is ready!"), { username: formattedUsername });
    1742         else
    1743             formatted = ' ' + sprintf(translate("* %(username)s is not ready."), { username: formattedUsername });
    1744         break;
    1745 
    1746     case "settings":
    1747         formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { message: translate('Game settings have been changed') }) + '[/font]';
    1748         break;
    1749 
    1750     default:
    1751         error(sprintf("Invalid chat message '%(message)s'", { message: uneval(msg) }));
    1752         return;
    1753     }
    1754 
    1755     g_ChatMessages.push(formatted);
    1756 
    1757     Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
    1758 }
    1759 
    17601691function toggleMoreOptions()
    17611692{
    17621693    Engine.GetGUIObjectByName("moreOptionsFade").hidden = !Engine.GetGUIObjectByName("moreOptionsFade").hidden;
    function resetReadyData()  
    18351766        return;
    18361767
    18371768    if (g_ReadyChanged < 1)
    1838         addChatMessage({ "type": "settings"});
     1769        addChatMessageGameSetup({ "type": "settings"});
    18391770    else if (g_ReadyChanged == 2 && !g_ReadyInit)
    18401771        return; // duplicate calls on init
    18411772    else
  • binaries/data/mods/public/gui/gamesetup/gamesetup.xml

    diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.xml b/binaries/data/mods/public/gui/gamesetup/gamesetup.xml
    index 4788977..d575793 100644
    a b  
    33<objects>
    44
    55    <script file="gui/common/network.js"/>
     6    <script file="gui/common/functions_chat.js"/>
    67    <script file="gui/common/functions_civinfo.js"/>
    78    <script file="gui/common/functions_global_object.js"/>
    89    <script file="gui/common/functions_utility.js"/>
  • binaries/data/mods/public/gui/session/messages.js

    diff --git a/binaries/data/mods/public/gui/session/messages.js b/binaries/data/mods/public/gui/session/messages.js
    index 0aef597..5c504c3 100644
    a b var g_NotificationsTypes =  
    4444        } else {
    4545            message["guid"] = guid;
    4646        }
    47         addChatMessage(message);
     47        addChatMessageSession(message);
    4848    },
    4949    "aichat": function(notification, player)
    5050    {
    var g_NotificationsTypes =  
    7474        } else {
    7575            message["guid"] = guid;
    7676        }
    77         addChatMessage(message);
     77        addChatMessageSession(message);
    7878    },
    7979    "defeat": function(notification, player)
    8080    {
    81         addChatMessage({
     81        addChatMessageSession({
    8282            "type": "defeat",
    8383            "guid": findGuidForPlayerID(g_PlayerAssignments, player),
    8484            "player": player
    var g_NotificationsTypes =  
    8888    },
    8989    "diplomacy": function(notification, player)
    9090    {
    91         addChatMessage({
     91        addChatMessageSession({
    9292            "type": "diplomacy",
    9393            "player": player,
    9494            "player1": notification.player1,
    var g_NotificationsTypes =  
    103103    },
    104104    "tribute": function(notification, player)
    105105    {
    106         addChatMessage({
     106        addChatMessageSession({
    107107            "type": "tribute",
    108108            "player": player,
    109109            "player1": notification.donator,
    var g_NotificationsTypes =  
    116116            return;
    117117        if (Engine.ConfigDB_GetValue("user", "gui.session.attacknotificationmessage") !== "true")
    118118            return;
    119         addChatMessage({
     119        addChatMessageSession({
    120120            "type": "attack",
    121121            "player": player,
    122122            "attacker": notification.attacker,
    function handleNetMessage(message)  
    259259            if (!message.hosts[host])
    260260            {
    261261                // Tell the user about the disconnection
    262                 addChatMessage({ "type": "disconnect", "guid": host });
     262                addChatMessageSession({ "type": "disconnect", "guid": host });
    263263
    264264                // Update the cached player data, so we can display the disconnection status
    265265                updatePlayerDataRemove(g_Players, host);
    function handleNetMessage(message)  
    275275                updatePlayerDataAdd(g_Players, host, message.hosts[host]);
    276276
    277277                // Tell the user about the connection
    278                 addChatMessage({ "type": "connect", "guid": host }, message.hosts);
     278                addChatMessageSession({ "type": "connect", "guid": host }, message.hosts);
    279279            }
    280280        }
    281281
    function handleNetMessage(message)  
    290290        break;
    291291
    292292    case "chat":
    293         addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
     293        addChatMessageSession({ "type": "message", "guid": message.guid, "text": message.text });
    294294        break;
    295295
    296296    case "aichat":
    297         addChatMessage({ "type": "message", "guid": message.guid, "text": message.text, "translate": true });
     297        addChatMessageSession({ "type": "message", "guid": message.guid, "text": message.text, "translate": true });
    298298        break;
    299299
    300300    case "rejoined":
    301         addChatMessage({ "type": "rejoined", "guid": message.guid});
     301        addChatMessageSession({ "type": "rejoined", "guid": message.guid});
    302302        break;
    303303       
    304304    // To prevent errors, ignore these message types that occur during autostart
    function submitChatDirectly(text)  
    318318        if (g_IsNetworked)
    319319            Engine.SendNetworkChat(text);
    320320        else
    321             addChatMessage({ "type": "message", "guid": "local", "text": text });
     321            addChatMessageSession({ "type": "message", "guid": "local", "text": text });
    322322    }
    323323}
    324324
    function submitChatInput()  
    385385            if (g_IsNetworked)
    386386                Engine.SendNetworkChat(text);
    387387            else
    388                 addChatMessage({ "type": "message", "guid": "local", "text": text });
     388                addChatMessageSession({ "type": "message", "guid": "local", "text": text });
    389389        }
    390390        input.caption = ""; // Clear chat input
    391391    }
    function submitChatInput()  
    395395    toggleChatWindow();
    396396}
    397397
    398 function addChatMessage(msg, playerAssignments)
    399 {
    400     // Default to global assignments, but allow overriding for when reporting
    401     // new players joining
    402     if (!playerAssignments)
    403         playerAssignments = g_PlayerAssignments;
    404 
    405     var playerColor, username;
    406 
    407     // No context by default. May be set by parseChatCommands().
    408     msg.context = "";
    409 
    410     if ("guid" in msg && playerAssignments[msg.guid])
    411     {
    412         var n = playerAssignments[msg.guid].player;
    413         // Observers have an ID of -1 which is not a valid index.
    414         if (n < 0)
    415             n = 0;
    416         playerColor = g_Players[n].color.r + " " + g_Players[n].color.g + " " + g_Players[n].color.b;
    417         username = escapeText(playerAssignments[msg.guid].name);
    418 
    419         // Parse in-line commands in regular messages.
    420         if (msg.type == "message")
    421             parseChatCommands(msg, playerAssignments);
    422     }
    423     else if (msg.type == "defeat" && msg.player)
    424     {
    425         [username, playerColor] = getUsernameAndColor(msg.player);
    426     }
    427     else if (msg.type == "message")
    428     {
    429         [username, playerColor] = getUsernameAndColor(msg.player);
    430         parseChatCommands(msg, playerAssignments);
    431     }
    432     else
    433     {
    434         playerColor = "255 255 255";
    435         username = translate("Unknown player");
    436     }
    437 
    438     var formatted;
    439 
    440     switch (msg.type)
    441     {
    442     case "connect":
    443         formatted = sprintf(translate("%(player)s is starting to rejoin the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    444         break;
    445     case "disconnect":
    446         formatted = sprintf(translate("%(player)s has left the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    447         break;
    448     case "rejoined":
    449         formatted = sprintf(translate("%(player)s has rejoined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    450         break;
    451     case "defeat":
    452         // In singleplayer, the local player is "You". "You has" is incorrect.
    453         if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
    454             formatted = translate("You have been defeated.");
    455         else
    456             formatted = sprintf(translate("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    457         break;
    458     case "diplomacy":
    459         var message;
    460         if (msg.player == Engine.GetPlayerID())
    461         {
    462             [username, playerColor] = getUsernameAndColor(msg.player1);
    463             if (msg.status == "ally")
    464                 message = translate("You are now allied with %(player)s.");
    465             else if (msg.status == "enemy")
    466                 message = translate("You are now at war with %(player)s.");
    467             else // (msg.status == "neutral")
    468                 message = translate("You are now neutral with %(player)s.");
    469         }
    470         else if (msg.player1 == Engine.GetPlayerID())
    471         {
    472             [username, playerColor] = getUsernameAndColor(msg.player);
    473             if (msg.status == "ally")
    474                 message = translate("%(player)s is now allied with you.");
    475             else if (msg.status == "enemy")
    476                 message = translate("%(player)s is now at war with you.");
    477             else // (msg.status == "neutral")
    478                 message = translate("%(player)s is now neutral with you.");
    479         }
    480         else // No need for other players to know of this.
    481             return;
    482 
    483         formatted = sprintf(message, { "player": '[color="'+ playerColor + '"]' + username + '[/color]' });
    484         break;
    485     case "tribute":
    486         if (msg.player != Engine.GetPlayerID())
    487             return;
    488 
    489         [username, playerColor] = getUsernameAndColor(msg.player1);
    490 
    491         // Format the amounts to proper English: 200 food, 100 wood, and 300 metal; 100 food; 400 wood and 200 stone
    492         let amounts = Object.keys(msg.amounts)
    493             .filter(function (type) { return msg.amounts[type] > 0; })
    494             .map(function (type) { return sprintf(translate("%(amount)s %(resourceType)s"), {
    495                 "amount": msg.amounts[type],
    496                 "resourceType": getLocalizedResourceName(type, "withinSentence")});
    497             });
    498 
    499         if (amounts.length > 1)
    500         {
    501             let lastAmount = amounts.pop();
    502             amounts = sprintf(translate("%(previousAmounts)s and %(lastAmount)s"), {
    503                 previousAmounts: amounts.join(translate(", ")),
    504                 lastAmount: lastAmount
    505             });
    506         }
    507 
    508         formatted = sprintf(translate("%(player)s has sent you %(amounts)s."), {
    509             player: "[color=\"" + playerColor + "\"]" + username + "[/color]",
    510             amounts: amounts
    511         });
    512         break;
    513     case "attack":
    514         if (msg.player != Engine.GetPlayerID())
    515             return;
    516 
    517         [username, playerColor] = getUsernameAndColor(msg.attacker);
    518         // Since livestock can be attacked/gathered by other players,
    519         // we display a more specific notification in this case to not confuse the player
    520         if (msg.targetIsDomesticAnimal)
    521             var message = translate("Your livestock have been attacked by %(attacker)s!");
    522         else
    523             var message = translate("You have been attacked by %(attacker)s!");
    524         formatted = sprintf(message, { attacker: "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    525         break;
    526     case "message":
    527         // May have been hidden by the 'team' command.
    528         if (msg.hide)
    529             return;
    530 
    531         var message;
    532         if ("translate" in msg && msg.translate)
    533         {
    534             message = translate(msg.text); // No need to escape, not a user message.
    535             if ("translateParameters" in msg && msg.translateParameters)
    536             {
    537                 var parameters = msg.parameters || {};
    538                 translateObjectKeys(parameters, msg.translateParameters);
    539                 message = sprintf(message, parameters);
    540             }
    541         }
    542         else
    543             message = escapeText(msg.text);
    544 
    545         if (msg.action)
    546         {
    547             if (msg.context !== "")
    548             {
    549                 formatted = sprintf(translate("(%(context)s) * %(user)s %(message)s"), {
    550                     context: msg.context,
    551                     user: "[color=\"" + playerColor + "\"]" + username + "[/color]",
    552                     message: message
    553                 });
    554             }
    555             else
    556             {
    557                 formatted = sprintf(translate("* %(user)s %(message)s"), {
    558                     user: "[color=\"" + playerColor + "\"]" + username + "[/color]",
    559                     message: message
    560                 });
    561             }
    562         }
    563         else
    564         {
    565             var userTag = sprintf(translate("<%(user)s>"), { user: username })
    566             var formattedUserTag = sprintf(translate("<%(user)s>"), { user: "[color=\"" + playerColor + "\"]" + username + "[/color]" })
    567             if (msg.context !== "")
    568             {
    569                 formatted = sprintf(translate("(%(context)s) %(userTag)s %(message)s"), {
    570                     context: msg.context,
    571                     userTag: formattedUserTag,
    572                     message: message
    573                 });
    574             }
    575             else
    576             {
    577                 formatted = sprintf(translate("%(userTag)s %(message)s"), { userTag: formattedUserTag, message: message});
    578             }
    579         }
    580         break;
    581     default:
    582         error(sprintf("Invalid chat message '%(message)s'", { message: uneval(msg) }));
    583         return;
    584     }
    585 
    586     chatMessages.push(formatted);
    587     chatTimers.push(setTimeout(removeOldChatMessages, CHAT_TIMEOUT));
    588 
    589     if (chatMessages.length > MAX_NUM_CHAT_LINES)
    590         removeOldChatMessages();
    591     else
    592         Engine.GetGUIObjectByName("chatText").caption = chatMessages.join("\n");
    593 }
    594 
    595398function removeOldChatMessages()
    596399{
    597400    clearTimeout(chatTimers[0]); // The timer only needs to be cleared when new messages bump old messages off
  • binaries/data/mods/public/gui/session/session.xml

    diff --git a/binaries/data/mods/public/gui/session/session.xml b/binaries/data/mods/public/gui/session/session.xml
    index d9ee7da..988d0db 100644
    a b  
    33<objects>
    44
    55<script file="gui/common/colorFades.js"/>
     6<script file="gui/common/functions_chat.js"/>
    67<script file="gui/common/functions_civinfo.js"/>
    78<script file="gui/common/functions_global_object.js"/>
    89<script file="gui/common/functions_utility.js"/>