Implements ready status into gamesetup. Fixes #2447.
This was SVN commit r15006.
This commit is contained in:
parent
4770e64449
commit
d1d7afe46c
BIN
binaries/data/mods/public/art/textures/ui/global/modern/gear-hover.png
(Stored with Git LFS)
Normal file
BIN
binaries/data/mods/public/art/textures/ui/global/modern/gear-hover.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
binaries/data/mods/public/art/textures/ui/global/modern/gear-press.png
(Stored with Git LFS)
Normal file
BIN
binaries/data/mods/public/art/textures/ui/global/modern/gear-press.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
binaries/data/mods/public/art/textures/ui/global/modern/gear.png
(Stored with Git LFS)
Normal file
BIN
binaries/data/mods/public/art/textures/ui/global/modern/gear.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -271,11 +271,15 @@
|
||||
<sprite name = "ModernDropDownArrow">
|
||||
<image texture = "global/modern/dropdown-arrow.png"
|
||||
real_texture_placement = "0 0 16 16"
|
||||
texture_size="0 0 16 16"
|
||||
size="0 6 16 22"
|
||||
/>
|
||||
</sprite>
|
||||
<sprite name = "ModernDropDownArrowHighlight">
|
||||
<image texture = "global/modern/dropdown-arrow.png"
|
||||
real_texture_placement = "0 0 16 16"
|
||||
texture_size="0 0 16 16"
|
||||
size="0 6 16 22"
|
||||
/>
|
||||
</sprite>
|
||||
<sprite name="ModernTickOn">
|
||||
@ -296,4 +300,19 @@
|
||||
size="0 0 22 22"
|
||||
/>
|
||||
</sprite>
|
||||
<sprite name="ModernGear">
|
||||
<image texture="global/modern/gear.png"
|
||||
texture_size="0 0 24 24"
|
||||
/>
|
||||
</sprite>
|
||||
<sprite name="ModernGearHover">
|
||||
<image texture="global/modern/gear-hover.png"
|
||||
texture_size="0 0 24 24"
|
||||
/>
|
||||
</sprite>
|
||||
<sprite name="ModernGearPressed">
|
||||
<image texture="global/modern/gear-press.png"
|
||||
texture_size="0 0 24 24"
|
||||
/>
|
||||
</sprite>
|
||||
</sprites>
|
||||
|
@ -46,7 +46,7 @@
|
||||
sprite2_pressed="ModernDropDownArrowHighlight"
|
||||
|
||||
buffer_zone="8"
|
||||
dropdown_size="216"
|
||||
dropdown_size="224"
|
||||
sprite_list="colour:12 12 12"
|
||||
sprite_selectarea="ModernDarkBoxWhite"
|
||||
textcolor_selected="white"
|
||||
|
@ -31,6 +31,19 @@ var g_ServerName;
|
||||
// (and therefore shouldn't send further messages to the network)
|
||||
var g_IsInGuiUpdate;
|
||||
|
||||
// Is this user ready
|
||||
var g_IsReady;
|
||||
|
||||
// There are some duplicate orders on init, we can ignore these [bool].
|
||||
var g_ReadyInit = true;
|
||||
|
||||
// If no one has changed ready status, we have no need to spam the settings changed message.
|
||||
// 2 - Host's initial ready, suppressed settings message, 1 - Will show settings message, <=0 - Suppressed settings message
|
||||
var g_ReadyChanged = 2;
|
||||
|
||||
// Has the game started?
|
||||
var g_GameStarted = false;
|
||||
|
||||
var g_PlayerAssignments = {};
|
||||
|
||||
// Default game setup attributes
|
||||
@ -98,7 +111,6 @@ function init(attribs)
|
||||
{
|
||||
cancelButton.tooltip = translate("Return to the lobby.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Called after the map data is loaded and cached
|
||||
@ -296,6 +308,7 @@ function initMain()
|
||||
}
|
||||
|
||||
Engine.GetGUIObjectByName("numPlayersSelection").hidden = true;
|
||||
Engine.GetGUIObjectByName("startGame").enabled = true;
|
||||
}
|
||||
|
||||
// Set up multiplayer/singleplayer bits:
|
||||
@ -414,19 +427,37 @@ function handleNetMessage(message)
|
||||
break;
|
||||
|
||||
case "players":
|
||||
var resetReady = false;
|
||||
var newPlayer = "";
|
||||
// Find and report all joinings/leavings
|
||||
for (var host in message.hosts)
|
||||
{
|
||||
if (! g_PlayerAssignments[host])
|
||||
{
|
||||
addChatMessage({ "type": "connect", "username": message.hosts[host].name });
|
||||
newPlayer = host;
|
||||
}
|
||||
}
|
||||
|
||||
for (var host in g_PlayerAssignments)
|
||||
{
|
||||
if (! message.hosts[host])
|
||||
{
|
||||
addChatMessage({ "type": "disconnect", "guid": host });
|
||||
if (g_PlayerAssignments[host].player != -1)
|
||||
resetReady = true; // Observers shouldn't reset ready.
|
||||
}
|
||||
}
|
||||
|
||||
// Update the player list
|
||||
g_PlayerAssignments = message.hosts;
|
||||
updatePlayerList();
|
||||
if (g_PlayerAssignments[newPlayer] && g_PlayerAssignments[newPlayer].player != -1)
|
||||
resetReady = true;
|
||||
|
||||
if (resetReady)
|
||||
resetReadyData(); // Observers shouldn't reset ready.
|
||||
updateReadyUI();
|
||||
if (g_IsController)
|
||||
sendRegisterGameStanza();
|
||||
break;
|
||||
@ -449,6 +480,18 @@ function handleNetMessage(message)
|
||||
addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
|
||||
break;
|
||||
|
||||
// Singular client to host message
|
||||
case "ready":
|
||||
g_ReadyChanged -= 1;
|
||||
if (g_ReadyChanged < 1 && g_PlayerAssignments[message.guid].player != -1)
|
||||
addChatMessage({ "type": "ready", "guid": message.guid, "ready": +message.status == 1 });
|
||||
if (!g_IsController)
|
||||
break;
|
||||
g_PlayerAssignments[message.guid].status = +message.status == 1;
|
||||
Engine.SetNetworkPlayerStatus(message.guid, +message.status);
|
||||
updateReadyUI();
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Unrecognised net message type "+message.type);
|
||||
}
|
||||
@ -597,17 +640,13 @@ function loadMapData(name)
|
||||
case "scenario":
|
||||
case "skirmish":
|
||||
g_MapData[name] = Engine.LoadMapSettings(name);
|
||||
translateObjectKeys(g_MapData[name], ["Name", "Description"]);
|
||||
break;
|
||||
|
||||
case "random":
|
||||
if (name == "random")
|
||||
g_MapData[name] = { settings: { "Name": translateWithContext("map", "Random"), "Description": translate("Randomly selects a map from the list") } };
|
||||
else
|
||||
{
|
||||
g_MapData[name] = parseJSONData(name+".json");
|
||||
translateObjectKeys(g_MapData[name], ["Name", "Description"]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -711,7 +750,7 @@ function selectNumPlayers(num)
|
||||
if (g_IsNetworked)
|
||||
Engine.AssignNetworkPlayer(player, "");
|
||||
else
|
||||
g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1} };
|
||||
g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1, "ready": 0} };
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,7 +867,7 @@ function selectMap(name)
|
||||
// Reset player assignments on map change
|
||||
if (!g_IsNetworked)
|
||||
{ // Slot 1
|
||||
g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1} };
|
||||
g_PlayerAssignments = { "local": { "name": translate("You"), "player": 1, "civ": "", "team": -1, "ready": 0} };
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -861,7 +900,7 @@ function launchGame()
|
||||
if (g_GameAttributes.map == "random")
|
||||
selectMap(Engine.GetGUIObjectByName("mapSelection").list_data[Math.floor(Math.random() *
|
||||
(Engine.GetGUIObjectByName("mapSelection").list.length - 1)) + 1]);
|
||||
|
||||
g_GameStarted = true;
|
||||
g_GameAttributes.settings.mapType = g_GameAttributes.mapType;
|
||||
var numPlayers = g_GameAttributes.settings.PlayerData.length;
|
||||
// Assign random civilizations to players with that choice
|
||||
@ -1244,6 +1283,9 @@ function onGameAttributesChange()
|
||||
|
||||
// Game attributes include AI settings, so update the player list
|
||||
updatePlayerList();
|
||||
|
||||
// We should have everyone confirm that the new settings are acceptable.
|
||||
resetReadyData();
|
||||
}
|
||||
|
||||
function updateGameAttributes()
|
||||
@ -1413,6 +1455,7 @@ function updatePlayerList()
|
||||
swapPlayers(guid, playerSlot);
|
||||
|
||||
Engine.SetNetworkGameAttributes(g_GameAttributes);
|
||||
updateReadyUI();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1494,14 +1537,22 @@ function submitChatInput()
|
||||
|
||||
function addChatMessage(msg)
|
||||
{
|
||||
var username = escapeText(msg.username || g_PlayerAssignments[msg.guid].name);
|
||||
var message = escapeText(msg.text);
|
||||
var username = "";
|
||||
if (msg.username)
|
||||
username = escapeText(msg.username);
|
||||
else if (msg.guid && g_PlayerAssignments[msg.guid])
|
||||
username = escapeText(g_PlayerAssignments[msg.guid].name);
|
||||
|
||||
var message = "";
|
||||
if (msg.text)
|
||||
message = escapeText(msg.text);
|
||||
|
||||
// TODO: Maybe host should have distinct font/color?
|
||||
var color = "white";
|
||||
|
||||
if (g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
|
||||
{ // Valid player who has been assigned - get player colour
|
||||
if (msg.guid && g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != -1)
|
||||
{
|
||||
// Valid player who has been assigned - get player colour
|
||||
var player = g_PlayerAssignments[msg.guid].player - 1;
|
||||
var mapName = g_GameAttributes.map;
|
||||
var mapData = loadMapData(mapName);
|
||||
@ -1516,13 +1567,13 @@ function addChatMessage(msg)
|
||||
switch (msg.type)
|
||||
{
|
||||
case "connect":
|
||||
var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font][color="gold"]'
|
||||
formatted = '[color="gold"]' + sprintf(translate("%(username)s has joined"), { username: formattedUsername });
|
||||
var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
|
||||
formatted = '[color="gold"]' + sprintf(translate("%(username)s has joined"), { username: formattedUsername }) + '[/color]';
|
||||
break;
|
||||
|
||||
case "disconnect":
|
||||
var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font][color="gold"]'
|
||||
formatted = '[color="gold"]' + sprintf(translate("%(username)s has left"), { username: formattedUsername });
|
||||
var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
|
||||
formatted = '[color="gold"]' + sprintf(translate("%(username)s has left"), { username: formattedUsername }) + '[/color]';
|
||||
break;
|
||||
|
||||
case "message":
|
||||
@ -1531,6 +1582,18 @@ function addChatMessage(msg)
|
||||
formatted = sprintf(translate("%(username)s %(message)s"), { username: formattedUsernamePrefix, message: message });
|
||||
break;
|
||||
|
||||
case "ready":
|
||||
var formattedUsername = '[font="sans-bold-13"][color="'+ color +'"]' + username + '[/color][/font]'
|
||||
if (msg.ready)
|
||||
formatted = '[color="gold"]*' + sprintf(translate("%(username)s is ready!"), { username: formattedUsername }) + '[/color]';
|
||||
else
|
||||
formatted = '[color="gold"]*' + sprintf(translate("%(username)s is not ready."), { username: formattedUsername }) + '[/color]';
|
||||
break;
|
||||
|
||||
case "settings":
|
||||
formatted = '[color="gold"][font="sans-bold-13"]*' + translate('Game settings have been changed.') + '[/font][/color]';
|
||||
break;
|
||||
|
||||
default:
|
||||
error(sprintf("Invalid chat message '%(message)s'", { message: uneval(msg) }));
|
||||
return;
|
||||
@ -1547,6 +1610,80 @@ function toggleMoreOptions()
|
||||
Engine.GetGUIObjectByName("moreOptions").hidden = !Engine.GetGUIObjectByName("moreOptions").hidden;
|
||||
}
|
||||
|
||||
function toggleReady()
|
||||
{
|
||||
g_IsReady = !g_IsReady;
|
||||
if (g_IsReady)
|
||||
{
|
||||
Engine.SendNetworkReady(1);
|
||||
Engine.GetGUIObjectByName("startGame").caption = translate("I'm not ready.");
|
||||
Engine.GetGUIObjectByName("startGame").tooltip = translate("State that you are not ready to play.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Engine.SendNetworkReady(0);
|
||||
Engine.GetGUIObjectByName("startGame").caption = translate("I'm ready!");
|
||||
Engine.GetGUIObjectByName("startGame").tooltip = translate("State that you are ready to play!");
|
||||
}
|
||||
}
|
||||
|
||||
function updateReadyUI()
|
||||
{
|
||||
var allReady = true;
|
||||
for (var guid in g_PlayerAssignments)
|
||||
{
|
||||
// We don't really care whether observers are ready.
|
||||
if (g_PlayerAssignments[guid].player == -1 || !g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1])
|
||||
continue;
|
||||
var pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[g_PlayerAssignments[guid].player - 1] : {};
|
||||
var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[g_PlayerAssignments[guid].player - 1] : {};
|
||||
if (g_PlayerAssignments[guid].status || !g_IsNetworked)
|
||||
Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = '[color="0 255 0"]' + getSetting(pData, pDefs, "Name") + '[/color]';
|
||||
else
|
||||
{
|
||||
Engine.GetGUIObjectByName("playerName[" + (g_PlayerAssignments[guid].player - 1) + "]").caption = getSetting(pData, pDefs, "Name");
|
||||
allReady = false;
|
||||
}
|
||||
}
|
||||
// AIs are always ready.
|
||||
for (var playerid = 0; playerid < MAX_PLAYERS; playerid++)
|
||||
{
|
||||
if (!g_GameAttributes.settings.PlayerData[playerid])
|
||||
continue;
|
||||
var pData = g_GameAttributes.settings.PlayerData ? g_GameAttributes.settings.PlayerData[playerid] : {};
|
||||
var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[playerid] : {};
|
||||
if (g_GameAttributes.settings.PlayerData[playerid].AI != "" || g_GameAttributes.settings.PlayerData[playerid].Name == "Unassigned")
|
||||
Engine.GetGUIObjectByName("playerName[" + playerid + "]").caption = '[color="0 255 0"]' + getSetting(pData, pDefs, "Name") + '[/color]';
|
||||
}
|
||||
// The host is not allowed to start until everyone is ready.
|
||||
if (g_IsNetworked && g_IsController)
|
||||
Engine.GetGUIObjectByName("startGame").enabled = allReady;
|
||||
}
|
||||
|
||||
function resetReadyData()
|
||||
{
|
||||
if (g_GameStarted)
|
||||
return;
|
||||
if (g_ReadyChanged < 1)
|
||||
addChatMessage({ "type": "settings"});
|
||||
else if (g_ReadyChanged == 2 && !g_ReadyInit)
|
||||
return; // duplicate calls on init
|
||||
else
|
||||
g_ReadyInit = false;
|
||||
g_ReadyChanged = 2;
|
||||
if (g_IsNetworked && g_IsController)
|
||||
{
|
||||
Engine.ClearAllPlayerReady();
|
||||
g_IsReady = true;
|
||||
Engine.SendNetworkReady(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_IsReady = false;
|
||||
Engine.GetGUIObjectByName("startGame").caption = translate("I'm ready!");
|
||||
Engine.GetGUIObjectByName("startGame").tooltip = translate("State that you accept the current settings and are ready to play!");
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Basic map filters API
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
<object style="TitleText" type="text" size="50%-128 4 50%+128 36">
|
||||
<translatableAttribute id="caption">Match Setup</translatableAttribute>
|
||||
</object>
|
||||
|
||||
|
||||
<object type="image" style="ModernDialog" size="50%-190 50%-80 50%+190 50%+80" name="loadingWindow">
|
||||
|
||||
<object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16">
|
||||
@ -32,19 +32,19 @@
|
||||
<action on="Tick">
|
||||
onTick();
|
||||
</action>
|
||||
|
||||
|
||||
<!-- Number of Players-->
|
||||
<object size="24 26 224 54">
|
||||
<object size="24 26 100%-24 54">
|
||||
|
||||
<!-- Number of Players-->
|
||||
<object size="0 0 150 28">
|
||||
<object size="0 0 50%-170 28">
|
||||
<object size="0 0 100% 100%" type="text" style="ModernRightLabelText">
|
||||
<translatableAttribute id="caption">Number of players:</translatableAttribute>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- Number of Players-->
|
||||
<object size="150 0 200 28">
|
||||
<object size="50%-170 0 50%-120 28">
|
||||
<object name="numPlayersText" size="0 0 100% 100%" type="text" style="ModernLeftLabelText"/>
|
||||
<object name="numPlayersSelection"
|
||||
type="dropdown"
|
||||
@ -61,20 +61,20 @@
|
||||
<!-- Player assignments -->
|
||||
<object size="24 59 100%-440 358" type="image" sprite="ModernDarkBoxGold" name="playerAssignmentsPannel">
|
||||
<object size="0 6 100% 30">
|
||||
<object name="playerNameHeading" type="text" style="ModernLabelText" size="0 0 20% 100%">
|
||||
<object name="playerNameHeading" type="text" style="ModernLabelText" size="0 0 22% 100%">
|
||||
<translatableAttribute id="caption">Player Name</translatableAttribute>
|
||||
</object>
|
||||
<object name="playerPlacementHeading" type="text" style="ModernLabelText" size="20%+5 0 50% 100%">
|
||||
<object name="playerPlacementHeading" type="text" style="ModernLabelText" size="22%+5 0 50%+35 100%">
|
||||
<translatableAttribute id="caption">Player Placement</translatableAttribute>
|
||||
</object>
|
||||
<object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85% 100%">
|
||||
<object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85%-26 100%">
|
||||
<translatableAttribute id="caption">Civilization</translatableAttribute>
|
||||
</object>
|
||||
<object name="civInfoButton"
|
||||
type="button"
|
||||
sprite="iconInfoGold"
|
||||
sprite_over="iconInfoWhite"
|
||||
size="82%-8 0 82%+8 16"
|
||||
size="67.5%+68 0 67.5%+84 16"
|
||||
tooltip_style="onscreenToolTip"
|
||||
>
|
||||
<translatableAttribute id="tooltip">View civilization info</translatableAttribute>
|
||||
@ -90,18 +90,20 @@
|
||||
<repeat count="8">
|
||||
<object name="playerBox[n]" size="0 0 100% 32" hidden="true">
|
||||
<object name="playerColour[n]" type="image" size="0 0 100% 100%"/>
|
||||
<object name="playerName[n]" type="text" style="ModernLabelText" size="0 2 20% 30"/>
|
||||
<object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="20%+5 2 50% 30" tooltip_style="onscreenToolTip">
|
||||
<object name="playerName[n]" type="text" style="ModernLabelText" size="0 2 22% 30"/>
|
||||
<object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="22%+5 2 50%+35 30" tooltip_style="onscreenToolTip">
|
||||
<translatableAttribute id="tooltip">Select player.</translatableAttribute>
|
||||
</object>
|
||||
<object name="playerConfig[n]" type="button" style="StoneButton" size="50%+5 6 50%+60 26"
|
||||
<object name="playerConfig[n]" type="button" style="StoneButton" size="50%+40 4 50%+64 28"
|
||||
tooltip_style="onscreenToolTip"
|
||||
font="sans-bold-stroke-12"
|
||||
sprite="ModernGear"
|
||||
sprite_over="ModernGearHover"
|
||||
sprite_pressed="ModernGearPressed"
|
||||
>
|
||||
<translatableAttribute id="caption">Settings</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Configure AI settings.</translatableAttribute>
|
||||
</object>
|
||||
<object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+65 2 85% 30" tooltip_style="onscreenToolTip">
|
||||
<object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+69 2 85% 30" tooltip_style="onscreenToolTip">
|
||||
<translatableAttribute id="tooltip">Select player's civilization.</translatableAttribute>
|
||||
</object>
|
||||
<object name="playerCivText[n]" type="text" style="ModernLabelText" size="50%+65 0 85% 30"/>
|
||||
@ -113,7 +115,7 @@
|
||||
</repeat>
|
||||
</object>
|
||||
</object>
|
||||
<object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPannelCover" hidden="true"/>
|
||||
<object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPanelCover" hidden="true"/>
|
||||
<!-- Map selection -->
|
||||
|
||||
|
||||
@ -138,7 +140,7 @@
|
||||
<object name="mapSelectionText" type="text" style="ModernLeftLabelText" size="0 64 100% 94" hidden="true"/>
|
||||
<object name="mapSizeText" type="text" style="ModernLeftLabelText" size="0 96 100% 126" hidden="true"/>
|
||||
</object>
|
||||
|
||||
|
||||
<object name="mapTypeSelection"
|
||||
type="dropdown"
|
||||
style="ModernDropDown"
|
||||
@ -169,7 +171,7 @@
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<object name="mapSize" size="100%-325 459 100%-25 487" type="dropdown" style="ModernDropDown" hidden="true" tooltip_style="onscreenToolTip">
|
||||
<object name="mapSize" size="100%-315 459 100%-25 487" type="dropdown" style="ModernDropDown" hidden="true" tooltip_style="onscreenToolTip">
|
||||
<translatableAttribute id="tooltip">Select map size. (Larger sizes may reduce performance.)</translatableAttribute>
|
||||
</object>
|
||||
|
||||
@ -187,7 +189,7 @@
|
||||
</object>
|
||||
|
||||
<!-- Chat window -->
|
||||
<object name="chatPanel" size="24 370 100%-440 100%-60" type="image" sprite="ModernDarkBoxGold">
|
||||
<object name="chatPanel" size="24 370 100%-440 100%-58" type="image" sprite="ModernDarkBoxGold">
|
||||
<object name="chatText" size="2 2 100%-2 100%-26" type="text" style="ChatPanel"/>
|
||||
|
||||
<object name="chatInput" size="4 100%-24 100%-76 100%-4" type="input" style="ModernInput">
|
||||
@ -207,12 +209,12 @@
|
||||
textcolor="white"
|
||||
sprite="BackgroundTranslucent"
|
||||
hidden="true"
|
||||
size="100%-700 100%-56 100%-312 100%-24"
|
||||
size="20 100%-56 100%-312 100%-24"
|
||||
>
|
||||
<translatableAttribute id="caption">[Tooltip text]</translatableAttribute>
|
||||
</object>
|
||||
|
||||
<!-- Start Button -->
|
||||
<!-- Start/Ready Button -->
|
||||
<object
|
||||
name="startGame"
|
||||
type="button"
|
||||
@ -223,7 +225,12 @@
|
||||
>
|
||||
<translatableAttribute id="caption">Start game!</translatableAttribute>
|
||||
<translatableAttribute id="tooltip">Start a new game with the current settings.</translatableAttribute>
|
||||
<action on="Press">launchGame();</action>
|
||||
<action on="Press">
|
||||
if (g_IsController)
|
||||
launchGame();
|
||||
else
|
||||
toggleReady();
|
||||
</action>
|
||||
</object>
|
||||
|
||||
<!-- Cancel Button -->
|
||||
@ -245,7 +252,7 @@
|
||||
]]>
|
||||
</action>
|
||||
</object>
|
||||
|
||||
|
||||
<!-- Options -->
|
||||
<object name="gameOptionsBox" size="100%-425 497 100%-25 525">
|
||||
<!-- More Options Button -->
|
||||
|
@ -344,6 +344,20 @@ void AssignNetworkPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int pla
|
||||
g_NetServer->AssignPlayer(playerID, guid);
|
||||
}
|
||||
|
||||
void SetNetworkPlayerStatus(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::string guid, int ready)
|
||||
{
|
||||
ENSURE(g_NetServer);
|
||||
|
||||
g_NetServer->SetPlayerReady(guid, ready);
|
||||
}
|
||||
|
||||
void ClearAllPlayerReady (ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
|
||||
{
|
||||
ENSURE(g_NetServer);
|
||||
|
||||
g_NetServer->ClearAllPlayerReady();
|
||||
}
|
||||
|
||||
void SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring message)
|
||||
{
|
||||
ENSURE(g_NetClient);
|
||||
@ -351,6 +365,13 @@ void SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstrin
|
||||
g_NetClient->SendChatMessage(message);
|
||||
}
|
||||
|
||||
void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message)
|
||||
{
|
||||
ENSURE(g_NetClient);
|
||||
|
||||
g_NetClient->SendReadyMessage(message);
|
||||
}
|
||||
|
||||
std::vector<CScriptValRooted> GetAIs(ScriptInterface::CxPrivate* pCxPrivate)
|
||||
{
|
||||
return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface));
|
||||
@ -861,7 +882,10 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
|
||||
scriptInterface.RegisterFunction<CScriptVal, &PollNetworkClient>("PollNetworkClient");
|
||||
scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
|
||||
scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
|
||||
scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus");
|
||||
scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
|
||||
scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat");
|
||||
scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
|
||||
scriptInterface.RegisterFunction<std::vector<CScriptValRooted>, &GetAIs>("GetAIs");
|
||||
scriptInterface.RegisterFunction<CScriptValRooted, &GetEngineInfo>("GetEngineInfo");
|
||||
|
||||
|
@ -87,6 +87,7 @@ CNetClient::CNetClient(CGame* game) :
|
||||
AddTransition(NCS_INITIAL_GAMESETUP, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
|
||||
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context);
|
||||
AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context);
|
||||
@ -214,6 +215,7 @@ void CNetClient::PostPlayerAssignmentsToScript()
|
||||
GetScriptInterface().Eval("({})", host);
|
||||
GetScriptInterface().SetProperty(host.get(), "name", std::wstring(it->second.m_Name), false);
|
||||
GetScriptInterface().SetProperty(host.get(), "player", it->second.m_PlayerID, false);
|
||||
GetScriptInterface().SetProperty(host.get(), "status", it->second.m_Status, false);
|
||||
GetScriptInterface().SetProperty(hosts.get(), it->first.c_str(), host, false);
|
||||
}
|
||||
|
||||
@ -254,6 +256,13 @@ void CNetClient::SendChatMessage(const std::wstring& text)
|
||||
SendMessage(&chat);
|
||||
}
|
||||
|
||||
void CNetClient::SendReadyMessage(const int status)
|
||||
{
|
||||
CReadyMessage readyStatus;
|
||||
readyStatus.m_Status = status;
|
||||
SendMessage(&readyStatus);
|
||||
}
|
||||
|
||||
bool CNetClient::HandleMessage(CNetMessage* message)
|
||||
{
|
||||
// Handle non-FSM messages first
|
||||
@ -419,6 +428,23 @@ bool CNetClient::OnChat(void* context, CFsmEvent* event)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetClient::OnReady(void* context, CFsmEvent* event)
|
||||
{
|
||||
ENSURE(event->GetType() == (uint)NMT_READY);
|
||||
|
||||
CNetClient* client = (CNetClient*)context;
|
||||
|
||||
CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
|
||||
|
||||
CScriptValRooted msg;
|
||||
client->GetScriptInterface().Eval("({'type':'ready'})", msg);
|
||||
client->GetScriptInterface().SetProperty(msg.get(), "guid", std::string(message->m_GUID), false);
|
||||
client->GetScriptInterface().SetProperty(msg.get(), "status", int (message->m_Status), false);
|
||||
client->PushGuiMessage(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetClient::OnGameSetup(void* context, CFsmEvent* event)
|
||||
{
|
||||
ENSURE(event->GetType() == (uint)NMT_GAME_SETUP);
|
||||
@ -453,6 +479,7 @@ bool CNetClient::OnPlayerAssignment(void* context, CFsmEvent* event)
|
||||
assignment.m_Enabled = true;
|
||||
assignment.m_Name = message->m_Hosts[i].m_Name;
|
||||
assignment.m_PlayerID = message->m_Hosts[i].m_PlayerID;
|
||||
assignment.m_Status = message->m_Hosts[i].m_Status;
|
||||
newPlayerAssignments[message->m_Hosts[i].m_GUID] = assignment;
|
||||
}
|
||||
|
||||
|
@ -164,6 +164,8 @@ public:
|
||||
void LoadFinished();
|
||||
|
||||
void SendChatMessage(const std::wstring& text);
|
||||
|
||||
void SendReadyMessage(const int status);
|
||||
|
||||
private:
|
||||
// Net message / FSM transition handlers
|
||||
@ -172,6 +174,7 @@ private:
|
||||
static bool OnHandshakeResponse(void* context, CFsmEvent* event);
|
||||
static bool OnAuthenticate(void* context, CFsmEvent* event);
|
||||
static bool OnChat(void* context, CFsmEvent* event);
|
||||
static bool OnReady(void* context, CFsmEvent* event);
|
||||
static bool OnGameSetup(void* context, CFsmEvent* event);
|
||||
static bool OnPlayerAssignment(void* context, CFsmEvent* event);
|
||||
static bool OnInGame(void* context, CFsmEvent* event);
|
||||
|
@ -46,6 +46,9 @@ struct PlayerAssignment
|
||||
|
||||
/// The player that the given host controls, or -1 if none (observer)
|
||||
i32 m_PlayerID;
|
||||
|
||||
/// Status - Ready or not: 0 for not ready, 1 for ready
|
||||
u8 m_Status;
|
||||
};
|
||||
|
||||
typedef std::map<CStr, PlayerAssignment> PlayerAssignmentMap; // map from GUID -> assignment
|
||||
|
@ -174,6 +174,10 @@ CNetMessage* CNetMessageFactory::CreateMessage(const void* pData,
|
||||
case NMT_CHAT:
|
||||
pNewMessage = new CChatMessage;
|
||||
break;
|
||||
|
||||
case NMT_READY:
|
||||
pNewMessage = new CReadyMessage;
|
||||
break;
|
||||
|
||||
case NMT_SIMULATION_COMMAND:
|
||||
pNewMessage = new CSimulationMessage(scriptInterface);
|
||||
|
@ -46,6 +46,7 @@ enum NetMessageType
|
||||
NMT_AUTHENTICATE, // Authentication stage
|
||||
NMT_AUTHENTICATE_RESULT,
|
||||
NMT_CHAT, // Common chat message
|
||||
NMT_READY,
|
||||
NMT_GAME_SETUP,
|
||||
NMT_PLAYER_ASSIGNMENT,
|
||||
|
||||
@ -118,11 +119,17 @@ START_NMT_CLASS_(Chat, NMT_CHAT)
|
||||
NMT_FIELD(CStrW, m_Message)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(Ready, NMT_READY)
|
||||
NMT_FIELD(CStr8, m_GUID)
|
||||
NMT_FIELD_INT(m_Status, u8, 1)
|
||||
END_NMT_CLASS()
|
||||
|
||||
START_NMT_CLASS_(PlayerAssignment, NMT_PLAYER_ASSIGNMENT)
|
||||
NMT_START_ARRAY(m_Hosts)
|
||||
NMT_FIELD(CStr8, m_GUID)
|
||||
NMT_FIELD(CStrW, m_Name)
|
||||
NMT_FIELD_INT(m_PlayerID, i8, 1)
|
||||
NMT_FIELD_INT(m_Status, u8, 1)
|
||||
NMT_END_ARRAY()
|
||||
END_NMT_CLASS()
|
||||
|
||||
|
@ -376,6 +376,8 @@ bool CNetServerWorker::RunStep()
|
||||
|
||||
std::vector<std::pair<int, CStr> > newAssignPlayer;
|
||||
std::vector<bool> newStartGame;
|
||||
std::vector<std::pair<CStr, int> > newPlayerReady;
|
||||
std::vector<bool> newPlayerResetReady;
|
||||
std::vector<std::string> newGameAttributes;
|
||||
std::vector<u32> newTurnLength;
|
||||
|
||||
@ -386,6 +388,8 @@ bool CNetServerWorker::RunStep()
|
||||
return false;
|
||||
|
||||
newStartGame.swap(m_StartGameQueue);
|
||||
newPlayerReady.swap(m_PlayerReadyQueue);
|
||||
newPlayerResetReady.swap(m_PlayerResetReadyQueue);
|
||||
newAssignPlayer.swap(m_AssignPlayerQueue);
|
||||
newGameAttributes.swap(m_GameAttributesQueue);
|
||||
newTurnLength.swap(m_TurnLengthQueue);
|
||||
@ -394,6 +398,12 @@ bool CNetServerWorker::RunStep()
|
||||
for (size_t i = 0; i < newAssignPlayer.size(); ++i)
|
||||
AssignPlayer(newAssignPlayer[i].first, newAssignPlayer[i].second);
|
||||
|
||||
for (size_t i = 0; i < newPlayerReady.size(); ++i)
|
||||
SetPlayerReady(newPlayerReady[i].first, newPlayerReady[i].second);
|
||||
|
||||
if (!newPlayerResetReady.empty())
|
||||
ClearAllPlayerReady();
|
||||
|
||||
if (!newGameAttributes.empty())
|
||||
UpdateGameAttributes(GetScriptInterface().ParseJSON(newGameAttributes.back()));
|
||||
|
||||
@ -548,6 +558,7 @@ void CNetServerWorker::SetupSession(CNetServerSession* session)
|
||||
|
||||
session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context);
|
||||
session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context);
|
||||
session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context);
|
||||
session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context);
|
||||
|
||||
session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context);
|
||||
@ -649,6 +660,7 @@ void CNetServerWorker::AddPlayer(const CStr& guid, const CStrW& name)
|
||||
assignment.m_Enabled = true;
|
||||
assignment.m_Name = name;
|
||||
assignment.m_PlayerID = playerID;
|
||||
assignment.m_Status = 0;
|
||||
m_PlayerAssignments[guid] = assignment;
|
||||
|
||||
// Send the new assignments to all currently active players
|
||||
@ -663,6 +675,21 @@ void CNetServerWorker::RemovePlayer(const CStr& guid)
|
||||
SendPlayerAssignments();
|
||||
}
|
||||
|
||||
void CNetServerWorker::SetPlayerReady(const CStr& guid, const int ready)
|
||||
{
|
||||
m_PlayerAssignments[guid].m_Status = ready;
|
||||
|
||||
SendPlayerAssignments();
|
||||
}
|
||||
|
||||
void CNetServerWorker::ClearAllPlayerReady()
|
||||
{
|
||||
for (PlayerAssignmentMap::iterator it = m_PlayerAssignments.begin(); it != m_PlayerAssignments.end(); ++it)
|
||||
it->second.m_Status = 0;
|
||||
|
||||
SendPlayerAssignments();
|
||||
}
|
||||
|
||||
void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
|
||||
{
|
||||
// Remove anyone who's already assigned to this player
|
||||
@ -690,6 +717,7 @@ void CNetServerWorker::ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage
|
||||
h.m_GUID = it->first;
|
||||
h.m_Name = it->second.m_Name;
|
||||
h.m_PlayerID = it->second.m_PlayerID;
|
||||
h.m_Status = it->second.m_Status;
|
||||
message.m_Hosts.push_back(h);
|
||||
}
|
||||
}
|
||||
@ -860,6 +888,22 @@ bool CNetServerWorker::OnChat(void* context, CFsmEvent* event)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetServerWorker::OnReady(void* context, CFsmEvent* event)
|
||||
{
|
||||
ENSURE(event->GetType() == (uint)NMT_READY);
|
||||
|
||||
CNetServerSession* session = (CNetServerSession*)context;
|
||||
CNetServerWorker& server = session->GetServer();
|
||||
|
||||
CReadyMessage* message = (CReadyMessage*)event->GetParamRef();
|
||||
|
||||
message->m_GUID = session->GetGUID();
|
||||
|
||||
server.Broadcast(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
|
||||
{
|
||||
ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
|
||||
@ -1053,6 +1097,18 @@ void CNetServer::AssignPlayer(int playerID, const CStr& guid)
|
||||
m_Worker->m_AssignPlayerQueue.push_back(std::make_pair(playerID, guid));
|
||||
}
|
||||
|
||||
void CNetServer::SetPlayerReady(const CStr& guid, int ready)
|
||||
{
|
||||
CScopeLock lock(m_Worker->m_WorkerMutex);
|
||||
m_Worker->m_PlayerReadyQueue.push_back(std::make_pair(guid, ready));
|
||||
}
|
||||
|
||||
void CNetServer::ClearAllPlayerReady()
|
||||
{
|
||||
CScopeLock lock(m_Worker->m_WorkerMutex);
|
||||
m_Worker->m_PlayerResetReadyQueue.push_back(false);
|
||||
}
|
||||
|
||||
void CNetServer::StartGame()
|
||||
{
|
||||
CScopeLock lock(m_Worker->m_WorkerMutex);
|
||||
|
@ -122,7 +122,19 @@ public:
|
||||
* The changes will be asynchronously propagated to all clients.
|
||||
*/
|
||||
void AssignPlayer(int playerID, const CStr& guid);
|
||||
|
||||
/**
|
||||
* Call from the GUI to update the player readiness.
|
||||
* The changes will be asynchronously propagated to all clients.
|
||||
*/
|
||||
void SetPlayerReady(const CStr& guid, int ready);
|
||||
|
||||
/**
|
||||
* Call from the GUI to set the all player readiness to 0.
|
||||
* The changes will be asynchronously propagated to all clients.
|
||||
*/
|
||||
void ClearAllPlayerReady();
|
||||
|
||||
/**
|
||||
* Call from the GUI to asynchronously notify all clients that they should start loading the game.
|
||||
*/
|
||||
@ -233,7 +245,9 @@ private:
|
||||
|
||||
void AddPlayer(const CStr& guid, const CStrW& name);
|
||||
void RemovePlayer(const CStr& guid);
|
||||
void SetPlayerReady(const CStr& guid, const int ready);
|
||||
void SendPlayerAssignments();
|
||||
void ClearAllPlayerReady();
|
||||
|
||||
void SetupSession(CNetServerSession* session);
|
||||
bool HandleConnect(CNetServerSession* session);
|
||||
@ -245,6 +259,7 @@ private:
|
||||
static bool OnAuthenticate(void* context, CFsmEvent* event);
|
||||
static bool OnInGame(void* context, CFsmEvent* event);
|
||||
static bool OnChat(void* context, CFsmEvent* event);
|
||||
static bool OnReady(void* context, CFsmEvent* event);
|
||||
static bool OnLoadedGame(void* context, CFsmEvent* event);
|
||||
static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event);
|
||||
static bool OnDisconnect(void* context, CFsmEvent* event);
|
||||
@ -320,6 +335,8 @@ private:
|
||||
// Queues for messages sent by the game thread:
|
||||
std::vector<std::pair<int, CStr> > m_AssignPlayerQueue; // protected by m_WorkerMutex
|
||||
std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex
|
||||
std::vector<std::pair<CStr, int> > m_PlayerReadyQueue; // protected by m_WorkerMutex
|
||||
std::vector<bool> m_PlayerResetReadyQueue; // protected by m_WorkerMutex
|
||||
std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex
|
||||
std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex
|
||||
};
|
||||
|
@ -402,7 +402,8 @@ bool CFsm::Update( unsigned int eventType, void* pEventParam )
|
||||
|
||||
// Lookup transition
|
||||
CFsmTransition* pTransition = GetTransition( m_CurrState, eventType );
|
||||
if ( !pTransition ) return false;
|
||||
if ( !pTransition )
|
||||
return false;
|
||||
|
||||
// Setup event parameter
|
||||
EventMap::iterator it = m_Events.find( eventType );
|
||||
@ -413,14 +414,16 @@ bool CFsm::Update( unsigned int eventType, void* pEventParam )
|
||||
}
|
||||
|
||||
// Valid transition?
|
||||
if ( !pTransition->ApplyConditions() ) return false;
|
||||
if ( !pTransition->ApplyConditions() )
|
||||
return false;
|
||||
|
||||
// Save the default state transition (actions might call SetNextState
|
||||
// to override this)
|
||||
SetNextState( pTransition->GetNextState() );
|
||||
|
||||
// Run transition actions
|
||||
if ( !pTransition->RunActions() ) return false;
|
||||
if ( !pTransition->RunActions() )
|
||||
return false;
|
||||
|
||||
// Switch state
|
||||
SetCurrState( GetNextState() );
|
||||
|
Loading…
Reference in New Issue
Block a user