diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg
index 29b22b062e..e512bf322d 100644
--- a/binaries/data/config/default.cfg
+++ b/binaries/data/config/default.cfg
@@ -190,6 +190,13 @@ hotkey.menu.toggle = "F10" ; Toggle in-game menu.
hotkey.menu.resign = "Alt+X" ; End current game session and return to main menu.
; > HOTKEYS ONLY
+
+
+
+hotkey.chat = Return ; Toggles chat window
+
+
+
hotkey.onlinehelp = "F1" ; Enable/disable online manual entry for current selection.
hotkey.music.toggle = "M" ; Enable/disable music.
hotkey.audio.toggle = "Ctrl+A" ; Enable/disable sound.
diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.js b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
index 588251c7ff..c3540598bf 100644
--- a/binaries/data/mods/public/gui/gamesetup/gamesetup.js
+++ b/binaries/data/mods/public/gui/gamesetup/gamesetup.js
@@ -14,7 +14,7 @@ var g_IsInGuiUpdate;
var g_PlayerAssignments = {};
// Default game setup attributes
-var g_GameAttributes = { "map": "" };
+var g_GameAttributes = { "map": ""};
// Number of players for currently selected map
var g_MaxPlayers = 8;
@@ -132,7 +132,7 @@ function handleNetMessage(message)
break;
case "start":
- Engine.SwitchGuiPage("page_loading.xml", { "attribs": g_GameAttributes });
+ Engine.SwitchGuiPage("page_loading.xml", { "attribs": g_GameAttributes, "isNetworked" : g_IsNetworked, "playerAssignments": g_PlayerAssignments});
break;
case "chat":
diff --git a/binaries/data/mods/public/gui/loading/loading.js b/binaries/data/mods/public/gui/loading/loading.js
index adf88b4e67..752f6b60e1 100644
--- a/binaries/data/mods/public/gui/loading/loading.js
+++ b/binaries/data/mods/public/gui/loading/loading.js
@@ -1,9 +1,20 @@
+var g_Data;
+
function init(data)
{
var mapName = "map";
if (data && data.attribs)
mapName = data.attribs.map;
+
+
+
+ if (data)
+ g_Data = data;
+
+
+
+
// Set to "hourglass" cursor.
setCursor("cursor-wait");
@@ -45,7 +56,7 @@ function reallyStartGame()
// to start the game (i.e. loading progress has reached 100%).
// Switch GUI from loading screen to game session.
- Engine.SwitchGuiPage("page_session_new.xml");
+ Engine.SwitchGuiPage("page_session_new.xml", g_Data);
// Restore default cursor.
setCursor ("arrow-default");
diff --git a/binaries/data/mods/public/gui/session_new/menu.js b/binaries/data/mods/public/gui/session_new/menu.js
index 8edc60dd59..96842808b6 100644
--- a/binaries/data/mods/public/gui/session_new/menu.js
+++ b/binaries/data/mods/public/gui/session_new/menu.js
@@ -38,4 +38,19 @@ function toggleMenu()
getGUIObjectByName("menu").hidden = false; // View menu
else
getGUIObjectByName("menu").hidden = true; // Hide menu
+}
+
+function toggleChatWindow()
+{
+ if (getGUIObjectByName("chatWindow").hidden)
+ {
+ getGUIObjectByName("chatInput").focus();
+ getGUIObjectByName("chatWindow").hidden = false; // View chat
+ }
+ else
+ {
+ getGUIObjectByName("chatWindow").hidden = true; // Hide chat
+ }
+
+ getGUIObjectByName("menu").hidden = true; // Hide menu
}
\ No newline at end of file
diff --git a/binaries/data/mods/public/gui/session_new/selection_details.js b/binaries/data/mods/public/gui/session_new/selection_details.js
index b5ae69eb14..69b5ac1e7d 100644
--- a/binaries/data/mods/public/gui/session_new/selection_details.js
+++ b/binaries/data/mods/public/gui/session_new/selection_details.js
@@ -29,21 +29,14 @@ function layoutSelectionSingle(entState)
}
// Fills out information that most entities have
-function displayGeneralInfo(playerState, entState, template)
+function displayGeneralInfo(entState, template)
{
- var civName = toTitleCase(playerState.civ);
- var color = playerState.color;
- var playerColor = color["r"]*255 + " " + color["g"]*255 + " " + color["b"]*255 + " " + color["a"]*255;
+ var civName = toTitleCase(g_Players[entState.player].civ);
+ var playerColor = g_Players[entState.player].color.r + " " + g_Players[entState.player].color.g + " " +
+ g_Players[entState.player].color.b+ " " + g_Players[entState.player].color.a;
+
var iconTooltip = "";
- // Rank Icon
-// var rankId = getRankCellId(entState);
-// getGUIObjectByName("sdRankIcon").cell_id = rankId;
-
- // Rank Title
-// var rankText = getRankTitle(getRankCellId(entState.template));
-// rankText = (rankText? rankText : "");
-
// Specific Name
var name = template.name.specific + getRankTitle(getRankCellId(entState.template));
getGUIObjectByName("sdSpecific").caption = name;
@@ -56,7 +49,7 @@ function displayGeneralInfo(playerState, entState, template)
getGUIObjectByName("sdSpecific").tooltip = "";
// Player Name
- getGUIObjectByName("sdPlayer").caption = playerState.name;
+ getGUIObjectByName("sdPlayer").caption = g_Players[entState.player].name;
getGUIObjectByName("sdPlayer").tooltip = getFormalCivName(civName);
getGUIObjectByName("sdPlayer").textcolor = playerColor;
@@ -130,7 +123,7 @@ function displayGeneralInfo(playerState, entState, template)
}
// Updates middle entity Selection Details Panel
-function updateSelectionDetails(simState)
+function updateSelectionDetails()
{
var detailsPanel = getGUIObjectByName("selectionDetails");
var commandsPanel = getGUIObjectByName("unitCommands");
@@ -152,10 +145,6 @@ function updateSelectionDetails(simState)
if (!entState)
return;
- var playerState = simState.players[entState.player];
- if (!playerState)
- return;
-
// Choose the highest ranked version of the primary selection
// Different selection details are shown based on whether multiple units or a single unit is selected
if (selection.length > 1)
@@ -166,7 +155,7 @@ function updateSelectionDetails(simState)
var template = Engine.GuiInterfaceCall("GetTemplateData", entState.template);
// Fill out general info and display it
- displayGeneralInfo(playerState, entState, template); // must come after layout functions
+ displayGeneralInfo(entState, template); // must come after layout functions
// Show Panels
detailsPanel.hidden = false;
diff --git a/binaries/data/mods/public/gui/session_new/session.js b/binaries/data/mods/public/gui/session_new/session.js
index a4947906ae..5fc91f6c9f 100644
--- a/binaries/data/mods/public/gui/session_new/session.js
+++ b/binaries/data/mods/public/gui/session_new/session.js
@@ -2,7 +2,6 @@ const GEOLOGY = "geology";
const FLORA = "flora";
const FAUNA = "fauna";
const SPECIAL = "special";
-const CAMP = "camp";
const GAIA = "Gaia"
const CART = "Cart";
@@ -19,6 +18,17 @@ const CELTS = "Celts";
const PERSIANS = "Persians";
const IBERIANS = "Iberians";
+// Chat data
+const maxNumChatLines = 30;
+var g_ChatMessages = [];
+var g_ChatTimers = [];
+
+// Network Mode
+var g_IsNetworked = false;
+
+// Cache the basic player data (name, civ, color)
+var g_Players = [];
+
// Cache dev-mode settings that are frequently or widely used
var g_DevSettings = {
controlAll: false
@@ -36,9 +46,55 @@ function init(initData, hotloadData)
startMusic();
}
+ if (initData)
+ {
+ g_IsNetworked = initData.isNetworked; // Set network mode
+ g_Players = getPlayerData(initData.playerAssignments); // Cache the player data
+ }
+
onSimulationUpdate();
}
+// Get the basic player data
+function getPlayerData(playerAssignments)
+{
+ var players = [];
+
+ var simState = Engine.GuiInterfaceCall("GetSimulationState");
+ if (!simState)
+ return players;
+
+ for (var i = 0; i < simState.players.length; i++)
+ {
+ var playerState = simState.players[i];
+ if (!playerState)
+ continue;
+
+ var name = playerState.name;
+ var civ = playerState.civ;
+ var color = {"r": 255, "g": 255, "b": 255, "a": 255};
+ color.r = playerState.color["r"]*255;
+ color.g = playerState.color["g"]*255;
+ color.b = playerState.color["b"]*255;
+ color.a = playerState.color["a"]*255;
+
+ var player = {"name": name, "civ": civ, "color": color};
+ players.push(player);
+ }
+
+ var i = 1;
+ if (playerAssignments)
+ {
+ for each (var playerAssignment in playerAssignments)
+ {
+ players[i].name = playerAssignment.name;
+ i++;
+ }
+ }
+
+ return players;
+}
+
function leaveGame()
{
stopMusic();
@@ -75,16 +131,97 @@ function handleNetMessage(message)
obj.hidden = false;
// TODO: we need to give players some way to exit
break;
+
default:
error("Unrecognised netstatus type "+message.status);
break;
}
break;
+ case "chat":
+ addChatMessage({ "type": "message", "username": message.username, "text": message.text });
+ break;
default:
error("Unrecognised net message type "+message.type);
}
}
+function submitChatInput()
+{
+ toggleChatWindow();
+
+ var input = getGUIObjectByName("chatInput");
+ var text = input.caption;
+ if (text.length)
+ {
+ if (g_IsNetworked)
+ Engine.SendNetworkChat(text);
+ else
+ getGUIObjectByName("chatText").caption = "Chat is not currently supported in single player mode.";
+
+ input.caption = "";
+ }
+}
+
+function addChatMessage(msg)
+{
+ // TODO: we ought to escape all values before displaying them,
+ // to prevent people inserting colours and newlines etc
+
+ var playerColor;
+
+ for (var i = 0; i < g_Players.length; i++)
+ {
+ if (msg.username == g_Players[i].name)
+ {
+ playerColor = g_Players[i].color.r + " " + g_Players[i].color.g + " " + g_Players[i].color.b;
+ break
+ }
+ }
+
+ var formatted;
+
+ switch (msg.type)
+ {
+ case "connect":
+ formatted = '<[color="' + playerColor + '"]' + msg.username + '[/color]> [color="64 64 64"]has joined[/color]';
+ break;
+
+ case "disconnect":
+ formatted = '<[color="' + playerColor + '"]' + msg.username + '[/color]> [color="64 64 64"]has left[/color]';
+ break;
+
+ case "message":
+ formatted = '<[color="' + playerColor + '"]' + msg.username + '[/color]> ' + msg.text;
+ break;
+
+ default:
+ error("Invalid chat message '" + uneval(msg) + "'");
+ return;
+ }
+
+ var timerExpiredFunction = function () { removeOldChatMessages(); }
+
+ g_ChatMessages.push(formatted);
+ g_ChatTimers.push(setTimeout(timerExpiredFunction, 30000));
+
+ if (g_ChatMessages.length > maxNumChatLines)
+ {
+ clearTimeout(g_ChatTimers[0]);
+ g_ChatTimers.shift();
+ g_ChatMessages.shift();
+ }
+
+ getGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
+}
+
+function removeOldChatMessages()
+{
+ clearTimeout(g_ChatTimers[0]);
+ g_ChatTimers.shift();
+ g_ChatMessages.shift();
+ getGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
+}
+
function onTick()
{
while (true)
@@ -125,7 +262,11 @@ function onSimulationUpdate()
updateDebug(simState);
updatePlayerDisplay(simState);
- updateSelectionDetails(simState);
+ updateSelectionDetails();
+
+ if (g_ChatTimers.length)
+ console.write(g_ChatTimers[0]);
+
}
function updateDebug(simState)
@@ -161,7 +302,6 @@ function updateDebug(simState)
function updatePlayerDisplay(simState)
{
var playerState = simState.players[Engine.GetPlayerID()];
-
if (!playerState)
return;
diff --git a/binaries/data/mods/public/gui/session_new/session.xml b/binaries/data/mods/public/gui/session_new/session.xml
index 3fee4406ed..9d115244f8 100644
--- a/binaries/data/mods/public/gui/session_new/session.xml
+++ b/binaries/data/mods/public/gui/session_new/session.xml
@@ -51,9 +51,14 @@
]]>
+
+
+
@@ -119,6 +124,27 @@
togglePause();
+
+
+
+
+
+
+
+
+
+
+ submitChatInput();
+
+
+
+ Send
+ submitChatInput();
+
+
+
@@ -127,7 +153,7 @@
type="image"
size="50%-180 50%-200 50%+180 50%+50"
hidden="true"
- z="50"
+ z="30"
>
Settings
@@ -178,10 +204,11 @@
toggleSettingsWindow();
+
+
+ Chat
+ toggleChatWindow();
+
+
- Pause Game
+ Pause
togglePause();
@@ -209,10 +247,10 @@
- Quit Game
+ Quit
toggleMenu();
@@ -226,6 +264,7 @@
style="wheatButtonFancy"
size="0 0 114 32"
tooltip_style="snToolTip"
+ z="30"
>
Menu
toggleMenu();
diff --git a/binaries/data/mods/public/gui/session_new/styles.xml b/binaries/data/mods/public/gui/session_new/styles.xml
index 2cf7bd7c5b..9a264e90c6 100644
--- a/binaries/data/mods/public/gui/session_new/styles.xml
+++ b/binaries/data/mods/public/gui/session_new/styles.xml
@@ -146,4 +146,13 @@
sprite="netStatusBackground"
/>
+
+