Ticket #4069: 4069_chat_history_v3.patch

File 4069_chat_history_v3.patch, 27.7 KB (added by elexis, 8 years ago)

Rewrote and added a number of things

  • binaries/data/config/default.cfg

    pan.y = 1  
    348348rotate.x = 3
    349349rotate.y = 2
    350350zoom.in = 5
    351351zoom.out = 4
    352352
     353[chat]
     354timestamp = false                   ; Show time chat message was posted
     355
     356[chat.session]
     357extended = true                     ; Whether to display the chat history
     358
    353359[lobby]
    354 chattimestamp = false               ; Show time chat message was posted
    355360history = 0                         ; Number of past messages to display on join
    356361room = "arena21"                    ; Default MUC room to join
    357362server = "lobby.wildfiregames.com"  ; Address of lobby server
    358363xpartamupp = "wfgbot21"             ; Name of the server-side xmpp client that manage games
    359364
  • binaries/data/mods/public/gui/common/styles.xml

     
    188188        scroll_bottom="false"
    189189        textcolor="white"
    190190        text_align="left"
    191191        text_valign="top"
    192192    />
     193
     194    <style name="ChatPanel"
     195        buffer_zone="5"
     196        font="sans-13"
     197        scrollbar="true"
     198        scrollbar_style="ModernScrollBar"
     199        scroll_bottom="true"
     200        textcolor="white"
     201        textcolor_selected="gold"
     202        text_align="left"
     203        text_valign="center"
     204    />
     205
    193206</styles>
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

    function addChatMessage(msg)  
    17921792    if (!g_FormatChatMessage[msg.type])
    17931793        return;
    17941794
    17951795    let user = colorizePlayernameByGUID(msg.guid || -1, msg.username || "");
    17961796
    1797     g_ChatMessages.push(g_FormatChatMessage[msg.type](msg, user));
     1797    let text = g_FormatChatMessage[msg.type](msg, user);
     1798
     1799    if (Engine.ConfigDB_GetValue("user", "chat.timestamp") == "true")
     1800        text = sprintf(translate("%(time)s %(message)s"), {
     1801            "time": sprintf(translate("\\[%(time)s]"), {
     1802                "time": Engine.FormatMillisecondsIntoDateString(new Date().getTime(), translate("HH:mm"))
     1803            }),
     1804            "message": text
     1805        });
     1806
     1807    g_ChatMessages.push(text);
    17981808
    17991809    Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
    18001810}
    18011811
    18021812function showMoreOptions(show)
  • binaries/data/mods/public/gui/gamesetup/styles.xml

     
    1 <?xml version="1.0" encoding="utf-8"?>
    2 
    3 <styles>
    4 
    5     <style name="ChatPanel"
    6         buffer_zone="5"
    7         font="sans-13"
    8         scrollbar="true"
    9         scrollbar_style="ModernScrollBar"
    10         scroll_bottom="true"
    11         textcolor="white"
    12         textcolor_selected="gold"
    13         text_align="left"
    14         text_valign="center"
    15     />
    16 
    17 </styles>
  • binaries/data/mods/public/gui/lobby/lobby.js

    const g_MapSizes = prepareForDropdown(g_  
    77 * Used for the gamelist-filtering.
    88 */
    99const g_MapTypes = prepareForDropdown(g_Settings && g_Settings.MapTypes);
    1010
    1111/**
    12  * Whether or not to display timestamps in the chat window.
    13  */
    14 const g_ShowTimestamp = Engine.ConfigDB_GetValue("user", "lobby.chattimestamp") == "true";
    15 
    16 /**
    1712 * Mute clients who exceed the rate of 1 message per second for this time
    1813 */
    1914const g_SpamBlockTimeframe = 5;
    2015
    2116/**
    function ircFormat(msg)  
    969964            "message": msg.text
    970965        });
    971966    }
    972967
    973968    // Add chat message timestamp
    974     if (!g_ShowTimestamp)
     969    if (Engine.ConfigDB_GetValue("user", "chat.timestamp") != "true")
    975970        return formattedMessage;
    976971
    977972    let time;
    978973    if (msg.datetime)
    979974    {
  • binaries/data/mods/public/gui/lobby/styles.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22
    33<styles>
    4     <style name="ChatPanel"
    5         buffer_zone="5"
    6         font="sans-13"
    7         scrollbar="true"
    8         scrollbar_style="ModernScrollBar"
    9         scroll_bottom="true"
    10         textcolor="white"
    11         textcolor_selected="gold"
    12         text_align="left"
    13         text_valign="center"
    14     />
    15 
    164    <style name="MapPlayerList"
    175        buffer_zone="8"
    186        font="sans-14"
    197        scrollbar="true"
    208        scrollbar_style="ModernScrollBar"
  • binaries/data/mods/public/gui/options/options.json

     
    8888        {
    8989            "type": "number",
    9090            "label": "Batch Training Size",
    9191            "tooltip": "Number of units trained per batch",
    9292            "parameters": { "config": "gui.session.batchtrainingsize", "min": 1, "max": 20 }
     93        },
     94        {
     95            "type": "boolean",
     96            "label": "Chat Timestamp",
     97            "tooltip": "Show time that messages are posted in the lobby, gamesetup and ingame chat.",
     98            "parameters": { "config": "chat.timestamp" }
    9399        }
    94100    ],
    95101    "graphicsSetting":
    96102    [
    97103        {
     
    243249        {
    244250            "type": "number",
    245251            "label": "Chat Backlog",
    246252            "tooltip": "Number of backlogged messages to load when joining the lobby",
    247253            "parameters": { "config": "lobby.history", "min": "0" }
    248         },
    249         {
    250             "type": "boolean",
    251             "label": "Chat Timestamp",
    252             "tooltip": "Show time that messages are posted in the lobby chat",
    253             "parameters": { "config": "lobby.chattimestamp" }
    254254        }
    255255    ]
    256256}
  • binaries/data/mods/public/gui/page_gamesetup.xml

     
    88    <include>common/sprites.xml</include>
    99    <include>common/styles.xml</include>
    1010
    1111    <include>gamesetup/setup.xml</include>
    1212    <include>gamesetup/sprites.xml</include>
    13     <include>gamesetup/styles.xml</include>
    1413    <include>gamesetup/gamesetup.xml</include>
    1514    <include>common/global.xml</include>
    1615</page>
  • binaries/data/mods/public/gui/session/chat_window.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22
    3 <object name="chatDialogPanel" size="50%-180 50%-66 50%+180 50%+54" type="image" hidden="true" sprite="genericPanel">
    4 
    5     <!-- Message addressee -->
    6     <object size="16 14 50 38" type="text" style="chatPanel">
    7         <translatableAttribute id="caption" context="chat input">To:</translatableAttribute>
    8     </object>
    9     <object size="75 12 100%-16 36" name="chatAddressee" type="dropdown" style="ModernDropDown" tooltip_style="sessionToolTipBold">
    10         <translatableAttribute id="tooltip" context="chat input">Select chatmessage addressee</translatableAttribute>
    11     </object>
    12 
    13     <!-- Message text -->
    14     <object size="16 46 50 70" type="text" style="chatPanel">
    15         <translatableAttribute id="caption" context="chat input">Text:</translatableAttribute>
    16     </object>
    17     <object name="chatInput" size="75 44 100%-16 68" type="input" style="ModernInput" max_length="80">
    18         <translatableAttribute id="tooltip" context="chat input">Type the message to send.</translatableAttribute>
    19         <action on="Press">submitChatInput();</action>
    20         <action on="Tab">
    21             let playernames = [];
    22             for (let player in g_PlayerAssignments)
    23                 playernames.push(g_PlayerAssignments[player].name);
    24             autoCompleteNick(this, playernames);
    25         </action>
     3<object
     4    name="chatDialogPanel"
     5    size="50%-210 50%-410 50%+210 50%+60"
     6    type="image"
     7    hidden="true"
     8    sprite="genericPanel"
     9>
     10    <!-- Chat History Page -->
     11    <object type="image" name="chatHistoryPage" size="0 0 100% 350" hidden="false">
     12
     13        <!-- Chat History Filter -->
     14        <object type="text" size="16 12 60 32" style="ModernLeftLabelText">
     15            <translatableAttribute id="caption" context="chat input">Filter:</translatableAttribute>
     16        </object>
     17
     18        <object
     19            type="dropdown"
     20            name="chatHistoryFilter"
     21            size="75 10 100%-16 34"
     22            style="ModernDropDown"
     23            tooltip_style="sessionToolTipBold"
     24        >
     25            <translatableAttribute id="tooltip" context="chat input">Filter the chat history.</translatableAttribute>
     26            <action on="SelectionChange">updateChatHistory();</action>
     27        </object>
     28
     29        <object
     30            type="text"
     31            name="chatHistory"
     32            size="10 46 100%-10 100%"
     33            sprite="ModernDarkBoxGold"
     34            style="ChatPanel"
     35        />
     36    </object>
     37
     38    <!-- Chat input elements -->
     39    <object name="chatPage" size="0 100%-120 100% 100%">
     40
     41        <!-- Message addressee -->
     42        <object size="16 100%-106 50 100%-82" type="text" style="ModernLeftLabelText">
     43            <translatableAttribute id="caption" context="chat input">To:</translatableAttribute>
     44        </object>
     45        <object
     46            name="chatAddressee"
     47            type="dropdown"
     48            size="75 100%-108 100%-16 100%-84"
     49            style="ModernDropDown"
     50            tooltip_style="sessionToolTipBold"
     51        >
     52            <translatableAttribute id="tooltip" context="chat input">Select chatmessage addressee.</translatableAttribute>
     53        </object>
     54
     55        <!-- Message text -->
     56        <object type="text" size="16 100%-74 50 100%-50" style="ModernLeftLabelText">
     57            <translatableAttribute id="caption" context="chat input">Text:</translatableAttribute>
     58        </object>
     59        <object
     60            type="input"
     61            name="chatInput"
     62            size="75 100%-76 100%-16 100%-52"
     63            style="ModernInput"
     64            max_length="80"
     65        >
     66            <translatableAttribute id="tooltip" context="chat input">Type the message to send.</translatableAttribute>
     67            <action on="Press">submitChatInput();</action>
     68            <action on="Tab">
     69                let playernames = [];
     70                for (let player in g_PlayerAssignments)
     71                    playernames.push(g_PlayerAssignments[player].name);
     72                autoCompleteNick(this, playernames);
     73            </action>
     74        </object>
     75
     76        <!-- Cancel Button -->
     77        <object size="16 100%-40 30%+16 100%-12" type="button" style="StoneButton">
     78            <translatableAttribute id="caption">Cancel</translatableAttribute>
     79            <action on="Press">closeChat();</action>
     80        </object>
     81
     82        <!-- Extended Chat Checkbox -->
     83        <object
     84            type="checkbox"
     85            name="extendedChat"
     86            checked="false"
     87            style="ModernTickBox"
     88            size="50%-50 100%-38 50%-24 100%-12"
     89        >
     90            <action on="Press">onChatWindowExtendedToggle();</action>
     91        </object>
     92
     93        <!-- Extended Chat Label -->
     94        <object type="text" size="50%-24 100%-38 50%+40 100%-12" text_align="left" textcolor="white">
     95            <translatableAttribute id="caption" context="chat">History</translatableAttribute>
     96        </object>
     97
     98        <!-- Send Button -->
     99        <object size="60%+16 100%-40 100%-16 100%-12" type="button" style="StoneButton">
     100            <translatableAttribute id="caption">Send</translatableAttribute>
     101            <action on="Press">submitChatInput();</action>
     102        </object>
    26103    </object>
    27 
    28     <!-- Cancel Button -->
    29     <object size="16 100%-40 30%+16 100%-12" type="button" style="StoneButton">
    30         <translatableAttribute id="caption">Cancel</translatableAttribute>
    31         <action on="Press">closeChat();</action>
    32     </object>
    33 
    34     <!-- Send Button -->
    35     <object size="60%+16 100%-40 100%-16 100%-12" type="button" style="StoneButton">
    36         <translatableAttribute id="caption">Send</translatableAttribute>
    37         <action on="Press">submitChatInput();</action>
    38     </object>
    39 
    40104</object>
  • binaries/data/mods/public/gui/session/diplomacy_window.xml

     
    99    <object type="text" style="TitleText" size="50%-96 -16 50%+96 16">
    1010        <translatableAttribute id="caption">Diplomacy</translatableAttribute>
    1111    </object>
    1212
    1313    <object name="diplomacyHeader" size="32 32 100%-32 64">
    14         <object name="diplomacyHeaderName" size="0 0 150 100%" type="text" style="chatPanel" ghost="true">
     14        <object name="diplomacyHeaderName" size="0 0 150 100%" type="text" style="ModernLeftLabelText" ghost="true">
    1515            <translatableAttribute id="caption">Name</translatableAttribute>
    1616        </object>
    17         <object name="diplomacyHeaderCiv" size="150 0 250 100%" type="text" style="chatPanel" ghost="true">
     17        <object name="diplomacyHeaderCiv" size="150 0 250 100%" type="text" style="ModernLeftLabelText" ghost="true">
    1818            <translatableAttribute id="caption">Civilization</translatableAttribute>
    1919        </object>
    20         <object name="diplomacyHeaderTeam" size="250 0 300 100%" type="text" style="chatPanel" ghost="true">
     20        <object name="diplomacyHeaderTeam" size="250 0 300 100%" type="text" style="ModernLeftLabelText" ghost="true">
    2121            <translatableAttribute id="caption">Team</translatableAttribute>
    2222        </object>
    23         <object name="diplomacyHeaderTheirs" size="300 0 360 100%" type="text" style="chatPanel" ghost="true">
     23        <object name="diplomacyHeaderTheirs" size="300 0 360 100%" type="text" style="ModernLeftLabelText" ghost="true">
    2424            <translatableAttribute id="caption">Theirs</translatableAttribute>
    2525        </object>
    26         <object name="diplomacyHeaderAlly" size="100%-180 0 100%-160 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold">
     26        <object name="diplomacyHeaderAlly" size="100%-180 0 100%-160 100%" type="text" style="ModernLeftLabelText" tooltip_style="sessionToolTipBold">
    2727            <translatableAttribute id="caption">A</translatableAttribute>
    2828            <translatableAttribute id="tooltip">Ally</translatableAttribute>
    2929        </object>
    30         <object name="diplomacyHeaderNeutral" size="100%-160 0 100%-140 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold">
     30        <object name="diplomacyHeaderNeutral" size="100%-160 0 100%-140 100%" type="text" style="ModernLeftLabelText" tooltip_style="sessionToolTipBold">
    3131            <translatableAttribute id="caption">N</translatableAttribute>
    3232            <translatableAttribute id="tooltip">Neutral</translatableAttribute>
    3333        </object>
    34         <object name="diplomacyHeaderEnemy" size="100%-140 0 100%-120 100%" type="text" style="chatPanel" tooltip_style="sessionToolTipBold">
     34        <object name="diplomacyHeaderEnemy" size="100%-140 0 100%-120 100%" type="text" style="ModernLeftLabelText" tooltip_style="sessionToolTipBold">
    3535            <translatableAttribute id="caption">E</translatableAttribute>
    3636            <translatableAttribute id="tooltip">Enemy</translatableAttribute>
    3737        </object>
    38         <object name="diplomacyHeaderTribute" size="100%-110 0 100% 100%" type="text" style="chatPanel">
     38        <object name="diplomacyHeaderTribute" size="100%-110 0 100% 100%" type="text" style="ModernLeftLabelText">
    3939            <translatableAttribute id="caption">Tribute</translatableAttribute>
    4040        </object>
    4141    </object>
     42
    4243    <object size="32 64 100%-32 384">
    4344        <repeat count="16">
    4445            <object name="diplomacyPlayer[n]" size="0 0 100% 20" type="image" hidden="false">
    45                 <object name="diplomacyPlayerName[n]" size="0 0 150 100%" type="text" style="chatPanel" ghost="true"/>
    46                 <object name="diplomacyPlayerCiv[n]" size="150 0 250 100%" type="text" style="chatPanel" ghost="true"/>
    47                 <object name="diplomacyPlayerTeam[n]" size="250 0 300 100%" type="text" style="chatPanel" ghost="true"/>
    48                 <object name="diplomacyPlayerTheirs[n]" size="300 0 360 100%" type="text" style="chatPanel" ghost="true"/>
     46                <object name="diplomacyPlayerName[n]" size="0 0 150 100%" type="text" style="ModernLeftLabelText" ghost="true"/>
     47                <object name="diplomacyPlayerCiv[n]" size="150 0 250 100%" type="text" style="ModernLeftLabelText" ghost="true"/>
     48                <object name="diplomacyPlayerTeam[n]" size="250 0 300 100%" type="text" style="ModernLeftLabelText" ghost="true"/>
     49                <object name="diplomacyPlayerTheirs[n]" size="300 0 360 100%" type="text" style="ModernLeftLabelText" ghost="true"/>
    4950
    5051                <!-- Diplomatic stance - selection -->
    5152                <object name="diplomacyPlayerAlly[n]" size="100%-180 0 100%-160 100%" type="button" style="StoneButton" hidden="true"/>
    5253                <object name="diplomacyPlayerNeutral[n]" size="100%-160 0 100%-140 100%" type="button" style="StoneButton" hidden="true"/>
    5354                <object name="diplomacyPlayerEnemy[n]" size="100%-140 0 100%-120 100%" type="button" style="StoneButton" hidden="true"/>
     
    7172                </object>
    7273            </object>
    7374        </repeat>
    7475    </object>
    7576
    76     <object name="diplomacyCeasefireCounter" size="32 100%-90 100%-32 100%-62" type="text" style="chatPanel" ghost="true"></object>
     77    <object name="diplomacyCeasefireCounter" size="32 100%-90 100%-32 100%-62" type="text" style="ModernLeftLabelText" ghost="true"></object>
    7778
    7879    <object size="50%-64 100%-50 50%+64 100%-22" type="button" style="StoneButton">
    7980        <translatableAttribute id="caption">Close</translatableAttribute>
    8081        <action on="Press">closeDiplomacy();</action>
    8182    </object>
  • binaries/data/mods/public/gui/session/menu.js

    function openChat(teamChat = false)  
    217217    let command = teamChat ? (g_IsObserver ? "/observers" : "/allies") : "";
    218218    chatAddressee.selected = chatAddressee.list_data.indexOf(command);
    219219
    220220    Engine.GetGUIObjectByName("chatInput").focus();
    221221    Engine.GetGUIObjectByName("chatDialogPanel").hidden = false;
     222
     223    updateChatHistory();
    222224}
    223225
    224226function closeChat()
    225227{
    226228    Engine.GetGUIObjectByName("chatInput").caption = "";
    227229    Engine.GetGUIObjectByName("chatInput").blur(); // Remove focus
    228230    Engine.GetGUIObjectByName("chatDialogPanel").hidden = true;
    229231}
    230232
     233function initChatWindow()
     234{
     235    let filters = prepareForDropdown(g_ChatHistoryFilters);
     236    let chatHistoryFilter = Engine.GetGUIObjectByName("chatHistoryFilter");
     237    chatHistoryFilter.list = filters.text;
     238    chatHistoryFilter.list_data = filters.key;
     239    chatHistoryFilter.selected = 0;
     240
     241    // Restore user preference
     242    if (Engine.ConfigDB_GetValue("user", "chat.session.extended") == "true")
     243        Engine.GetGUIObjectByName("extendedChat").checked = true;
     244
     245    resizeChatWindow();
     246}
     247
     248function resizeChatWindow()
     249{
     250    // Hide the panel
     251    let chatHistoryPage = Engine.GetGUIObjectByName("chatHistoryPage");
     252    let extended = Engine.GetGUIObjectByName("extendedChat").checked;
     253    chatHistoryPage.hidden = !extended;
     254
     255    // Resize the window
     256    let chatDialogPanel = Engine.GetGUIObjectByName("chatDialogPanel");
     257    let chatPage = Engine.GetGUIObjectByName("chatPage");
     258    let panelSize = chatDialogPanel.size;
     259    let topOffset = 60;
     260    let height = -chatPage.size.top + (extended ? chatHistoryPage.size.bottom : 0);
     261    panelSize.top = -height / 2 - topOffset;
     262    panelSize.bottom = height / 2 - topOffset;
     263    chatDialogPanel.size = panelSize;
     264}
     265
     266function updateChatHistory()
     267{
     268    if (Engine.GetGUIObjectByName("chatDialogPanel").hidden ||
     269        !Engine.GetGUIObjectByName("extendedChat").checked)
     270        return;
     271
     272    let chatHistoryFilter = Engine.GetGUIObjectByName("chatHistoryFilter");
     273    let selected = chatHistoryFilter.list_data[chatHistoryFilter.selected];
     274
     275    Engine.GetGUIObjectByName("chatHistory").caption =
     276        g_ChatHistory.filter(msg => msg.filter[selected]).map(msg =>
     277            Engine.ConfigDB_GetValue("user", "chat.timestamp") == "true" ?
     278                sprintf(translate("%(time)s %(message)s"), {
     279                    "time": msg.timePrefix,
     280                    "message": msg.txt
     281                }) :
     282                msg.txt
     283        ).join("\n");
     284}
     285
     286function onChatWindowExtendedToggle()
     287{
     288    // Save user preference
     289    let extended = Engine.GetGUIObjectByName("extendedChat").checked.toString();
     290    Engine.ConfigDB_CreateValue("user", "chat.session.extended", extended);
     291    Engine.ConfigDB_WriteValueToFile("user", "chat.session.extended", extended, "config/user.cfg");
     292
     293    resizeChatWindow();
     294
     295    Engine.GetGUIObjectByName("chatInput").focus();
     296}
     297
    231298function openDiplomacy()
    232299{
    233300    closeOpenDialogs();
    234301
    235302    if (g_ViewedPlayer < 1)
  • binaries/data/mods/public/gui/session/messages.js

    const g_ChatTimeout = 30;  
    1313 * Maximum number of lines to display simultaneously.
    1414 */
    1515const g_ChatLines = 20;
    1616
    1717/**
    18  * The strings to be displayed including sender and formating.
     18 * The currently displayed strings, limited by the given timeframe and limit above.
    1919 */
    2020var g_ChatMessages = [];
    2121
    2222/**
     23 * All unparsed chat messages received since connect, including timestamp.
     24 */
     25var g_ChatHistory = [];
     26
     27/**
    2328 * Holds the timer-IDs used for hiding the chat after g_ChatTimeout seconds.
    2429 */
    2530var g_ChatTimers = [];
    2631
    2732/**
    var g_IsChatAddressee = {  
    170175
    171176    "/msg": (senderID, addresseeGUID) =>
    172177        addresseeGUID == Engine.GetPlayerGUID()
    173178};
    174179
     180var g_ChatHistoryFilters = [
     181    {
     182        "key": "all",
     183        "text": translateWithContext("chat history filter", "Chat and notifications"),
     184        "filter": (msg, senderID) => true
     185    },
     186    {
     187        "key": "chat",
     188        "text": translateWithContext("chat history filter", "Chat messages"),
     189        "filter": (msg, senderID) => msg.type == "message"
     190    },
     191    {
     192        "key": "player",
     193        "text": translateWithContext("chat history filter", "Players chat"),
     194        "filter": (msg, senderID) =>
     195            msg.type == "message" && senderID > 0 && !isPlayerObserver(senderID)
     196    },
     197    {
     198        "key": "ally",
     199        "text": translateWithContext("chat history filter", "Ally chat"),
     200        "filter": (msg, senderID) =>
     201            msg.type == "message" &&
     202            msg.cmd && msg.cmd == "/allies" &&
     203            g_Players[Engine.GetPlayerID()] &&
     204            g_Players[Engine.GetPlayerID()].isAlly[senderID]
     205    },
     206    {
     207        "key": "enemy",
     208        "text": translateWithContext("chat history filter", "Enemy chat"),
     209        "filter": (msg, senderID) =>
     210            msg.type == "message" &&
     211            msg.cmd && msg.cmd == "/enemies" &&
     212            g_Players[Engine.GetPlayerID()] &&
     213            g_Players[Engine.GetPlayerID()].isEnemy[senderID]
     214    },
     215    {
     216        "key": "observer",
     217        "text": translateWithContext("chat history filter", "Observer chat"),
     218        "filter": (msg, senderID) =>
     219            msg.type == "message" &&
     220            msg.cmd && msg.cmd == "/observers"
     221    },
     222    {
     223        "key": "private",
     224        "text": translateWithContext("chat history filter", "Private chat"),
     225        "filter": (msg, senderID) => !!msg.isVisiblePM
     226    }
     227];
     228
    175229var g_PlayerStateMessages = {
    176230    "won": translate("You have won!"),
    177231    "defeated": translate("You have been defeated!")
    178232};
    179233
    function addChatMessage(msg)  
    701755
    702756    let formatted = g_FormatChatMessage[msg.type](msg);
    703757    if (!formatted)
    704758        return;
    705759
     760    // Update chat overlay
    706761    g_ChatMessages.push(formatted);
    707762    g_ChatTimers.push(setTimeout(removeOldChatMessage, g_ChatTimeout * 1000));
    708763
    709764    if (g_ChatMessages.length > g_ChatLines)
    710765        removeOldChatMessage();
    711766    else
    712767        Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
     768
     769    // Save to chat history
     770    let historical = {
     771        "txt": formatted,
     772        "timePrefix": sprintf(translate("\\[%(time)s]"), {
     773            "time": Engine.FormatMillisecondsIntoDateString(new Date().getTime(), translate("HH:mm"))
     774        }),
     775        "filter": {}
     776    };
     777
     778    // Apply the filters now before diplomacies or playerstates change
     779    let senderID = msg.guid && g_PlayerAssignments[msg.guid] ? g_PlayerAssignments[msg.guid].player : 0;
     780    for (let filter of g_ChatHistoryFilters)
     781        historical.filter[filter.key] = filter.filter(msg, senderID);
     782
     783    g_ChatHistory.push(historical);
     784    updateChatHistory();
    713785}
    714786
    715787/**
    716788 * Called when the timer has run out for the oldest chatmessage or when the message limit is reached.
    717789 */
    function formatChatCommand(msg)  
    859931    });
    860932}
    861933
    862934/**
    863935 * Checks if the current user is an addressee of the chatmessage sent by another player.
    864  * Sets the context of that message.
     936 * Sets the context and potentially addresseeGUID of that message.
    865937 * Returns true if the message should be displayed.
    866938 *
    867939 * @param {Object} msg
    868940 */
    869941function parseChatAddressee(msg)
    870942{
    871943    if (msg.text[0] != '/')
    872944        return true;
    873945
    874946    // Split addressee command and message-text
    875     let cmd = msg.text.split(/\s/)[0];
    876     msg.text = msg.text.substr(cmd.length + 1);
    877 
    878     if (cmd == "/ally")
    879         cmd = "/allies";
    880 
    881     if (cmd == "/enemy")
    882         cmd = "/enemies";
    883 
    884     if (cmd == "/observer")
    885         cmd = "/observers";
     947    msg.cmd = msg.text.split(/\s/)[0];
     948    msg.text = msg.text.substr(msg.cmd.length + 1);
    886949
    887950    // GUID for players and observers, ID for bots
    888951    let senderID = (g_PlayerAssignments[msg.guid] || msg).player;
    889952    let isSender = msg.guid ? msg.guid == Engine.GetPlayerGUID() : senderID == Engine.GetPlayerID();
    890953
    891954    // Parse private message
    892     let isPM = cmd == "/msg";
     955    let isPM = msg.cmd == "/msg";
    893956    let addresseeGUID;
    894957    let addresseeIndex;
    895958    if (isPM)
    896959    {
    897960        addresseeGUID = matchUsername(msg.text);
    function parseChatAddressee(msg)  
    910973        msg.text = msg.text.substr(addressee.name.length + 1);
    911974        addresseeIndex = addressee.player;
    912975    }
    913976
    914977    // Set context string
    915     if (!g_ChatAddresseeContext[cmd])
     978    if (!g_ChatAddresseeContext[msg.cmd])
    916979    {
    917980        if (isSender)
    918             warn("Unknown chat command: " + cmd);
     981            warn("Unknown chat command: " + msg.cmd);
    919982        return false;
    920983    }
    921     msg.context = g_ChatAddresseeContext[cmd];
     984    msg.context = g_ChatAddresseeContext[msg.cmd];
    922985
    923986    // For observers only permit public- and observer-chat and PM to observers
    924987    if (isPlayerObserver(senderID) &&
    925         (isPM && !isPlayerObserver(addresseeIndex) || !isPM && cmd != "/observers"))
     988        (isPM && !isPlayerObserver(addresseeIndex) || !isPM && msg.cmd != "/observers"))
    926989        return false;
    927990
    928     return isSender || g_IsChatAddressee[cmd](senderID, addresseeGUID);
     991    let visible = isSender || g_IsChatAddressee[msg.cmd](senderID, addresseeGUID);
     992    msg.isVisiblePM = isPM && visible;
     993
     994    return visible;
    929995}
    930996
    931997/**
    932998 * Returns the guid of the user with the longest name that is a prefix of the given string.
    933999 */
  • binaries/data/mods/public/gui/session/session.js

    function init(initData, hotloadData)  
    292292    // If in Atlas editor, disable the exit button
    293293    if (Engine.IsAtlasRunning())
    294294        Engine.GetGUIObjectByName("menuExitButton").enabled = false;
    295295
    296296    initHotkeyTooltips();
     297    initChatWindow();
    297298
    298299    if (hotloadData)
    299300        g_Selection.selected = hotloadData.selection;
    300301
    301302    sendLobbyPlayerlistUpdate();
  • binaries/data/mods/public/gui/session/session.xml

     
    6969        <object name="notificationText" size="0 0 100% 100%" type="text" style="notificationPanel" ghost="true"/>
    7070    </object>
    7171
    7272    <!-- Chat messages -->
    7373    <object name="chatPanel" size="0 130 100% 100%-240" type="image" ghost="true" z="0" absolute="true">
    74         <object name="chatText" size="3 1 100%-1 100%-1" type="text" style="chatPanel" ghost="true"/>
     74        <object name="chatText" size="3 1 100%-1 100%-1" type="text" style="chatPanelOverlay" ghost="true"/>
    7575    </object>
    7676
    7777    <!-- Entity selection state text -->
    7878    <object name="debugEntityState"
    7979        type="text"
  • binaries/data/mods/public/gui/session/styles.xml

     
    229229    />
    230230
    231231    <!-- ================================  ================================ -->
    232232    <!-- Misc Styles -->
    233233    <!-- ================================  ================================ -->
    234     <style name="chatPanel"
     234    <style name="chatPanelOverlay"
    235235        buffer_zone="5"
    236236        font="sans-bold-stroke-14"
    237237        textcolor="white"
    238238        textcolor_selected="white"
    239239        text_align="left"