Core: Added basic support for Spectators

TODO: Someone modify the files for cnc (chrome / rules)
This commit is contained in:
geckosoft
2010-10-31 03:57:03 +01:00
parent b9c40ad3ce
commit 030bd4b28d
18 changed files with 418 additions and 186 deletions

View File

@@ -56,7 +56,7 @@ namespace OpenRA.Network
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise. public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
public bool Closed; // host has explicitly closed this slot. public bool Closed; // host has explicitly closed this slot.
public string MapPlayer; // playerReference to bind against. public string MapPlayer; // playerReference to bind against.
public bool Spectator = false; // Spectating or not
// todo: more stuff? // todo: more stuff?
} }

View File

@@ -78,7 +78,7 @@ namespace OpenRA
PlayerName = client.Name; PlayerName = client.Name;
InternalName = pr.Name; InternalName = pr.Name;
Country = world.GetCountries() Country = world.GetCountries()
.FirstOrDefault(c => client != null && client.Country == c.Race) .FirstOrDefault(c => client != null && client.Country == c.Race )
?? world.GetCountries().Random(world.SharedRandom); ?? world.GetCountries().Random(world.SharedRandom);
ClientIndex = client.Index; ClientIndex = client.Index;

View File

@@ -40,6 +40,9 @@ namespace OpenRA.Server
const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit const int MasterPingInterval = 60 * 3; // 3 minutes. server has a 5 minute TTL for games, so give ourselves a bit
// of leeway. // of leeway.
public static int MaxSpectators = 4; // How many spectators to allow // @todo Expose this as an option
static int lastPing = 0; static int lastPing = 0;
static bool isInternetServer; static bool isInternetServer;
static string masterServerUrl; static string masterServerUrl;
@@ -135,6 +138,12 @@ namespace OpenRA.Server
.Where(s => s != null) .Where(s => s != null)
.Select((s, i) => { s.Index = i; return s; }) .Select((s, i) => { s.Index = i; return s; })
.ToList(); .ToList();
// Generate slots for spectators
for (int i = 0; i < MaxSpectators; i++)
{
lobbyInfo.Slots.Add(new Session.Slot { Spectator = true, Index = lobbyInfo.Slots.Count(), MapPlayer = null, Bot = null});
}
} }
/* lobby rework todo: /* lobby rework todo:
@@ -283,6 +292,8 @@ namespace OpenRA.Server
static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr) static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr)
{ {
if (pr == null)
return;
if (pr.LockColor) if (pr.LockColor)
{ {
c.Color1 = pr.Color; c.Color1 = pr.Color;
@@ -358,6 +369,13 @@ namespace OpenRA.Server
SyncLobbyInfo(); SyncLobbyInfo();
return true; return true;
}}, }},
{ "spectator",
s =>
{
// GetClient(conn).Slot = -1; /* observer */
SyncLobbyInfo();
return true;
}},
{ "team", { "team",
s => s =>
{ {
@@ -411,7 +429,7 @@ namespace OpenRA.Server
var cl = GetClient(conn); var cl = GetClient(conn);
cl.Slot = slot; cl.Slot = slot;
SyncClientToPlayerReference(cl, Map.Players[slotData.MapPlayer]); SyncClientToPlayerReference(cl, slotData.MapPlayer != null ? Map.Players[slotData.MapPlayer] : null);
SyncLobbyInfo(); SyncLobbyInfo();
return true; return true;

View File

@@ -158,7 +158,7 @@ namespace OpenRA.Traits
void DrawUnitPath(Actor self) void DrawUnitPath(Actor self)
{ {
if (!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return; if (self.World.LocalPlayer == null ||!self.World.LocalPlayer.PlayerActor.Trait<DeveloperMode>().PathDebug) return;
var activity = self.GetCurrentActivity(); var activity = self.GetCurrentActivity();
var mobile = self.TraitOrDefault<IMove>(); var mobile = self.TraitOrDefault<IMove>();

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Widgets.Delegates
{ {
public class LobbyDelegate : IWidgetDelegate public class LobbyDelegate : IWidgetDelegate
{ {
Widget Players, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost; Widget Players, LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost, EmptySpectatorSlotTemplateHost;
Dictionary<string, string> CountryNames; Dictionary<string, string> CountryNames;
string MapUid; string MapUid;
@@ -44,6 +44,7 @@ namespace OpenRA.Widgets.Delegates
RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE"); RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY"); EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST"); EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
EmptySpectatorSlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_SPECTATOR");
var mapPreview = lobby.GetWidget<MapPreviewWidget>("LOBBY_MAP_PREVIEW"); var mapPreview = lobby.GetWidget<MapPreviewWidget>("LOBBY_MAP_PREVIEW");
mapPreview.Map = () => Map; mapPreview.Map = () => Map;
@@ -71,6 +72,7 @@ namespace OpenRA.Widgets.Delegates
}; };
CountryNames = Rules.Info["world"].Traits.WithInterface<OpenRA.Traits.CountryInfo>().ToDictionary(a => a.Race, a => a.Name); CountryNames = Rules.Info["world"].Traits.WithInterface<OpenRA.Traits.CountryInfo>().ToDictionary(a => a.Race, a => a.Name);
CountryNames.Add("random", "Random"); CountryNames.Add("random", "Random");
var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON"); var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON");
@@ -232,25 +234,48 @@ namespace OpenRA.Widgets.Delegates
{ {
if (Game.IsHost) if (Game.IsHost)
{ {
template = EmptySlotTemplateHost.Clone(); if (slot.Spectator)
var name = template.GetWidget<ButtonWidget>("NAME");
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null)? "Open" : "Bot: " + s.Bot;
name.OnMouseUp = _ =>
{ {
if (s.Closed) template = EmptySlotTemplateHost.Clone();
var btn = template.GetWidget<ButtonWidget>("JOIN");
var name = template.GetWidget<ButtonWidget>("NAME");
btn.GetText = () => "Spectate in this slot";
name.GetText = () => s.Closed ? "Closed" : "Open";
name.OnMouseUp = _ =>
{ {
s.Bot = null; if (s.Closed)
orderManager.IssueOrder(Order.Command("slot_open " + s.Index)); {
} orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
else }
{
if (s.Bot == null && Map.Players[s.MapPlayer].AllowBots)
orderManager.IssueOrder(Order.Command("slot_bot {0} HackyAI".F(s.Index)));
else else
{
orderManager.IssueOrder(Order.Command("slot_close " + s.Index)); orderManager.IssueOrder(Order.Command("slot_close " + s.Index));
} }
return true; return true;
}; };
}
else
{
template = EmptySlotTemplateHost.Clone();
var name = template.GetWidget<ButtonWidget>("NAME");
name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : "Bot: " + s.Bot;
name.OnMouseUp = _ =>
{
if (s.Closed)
{
s.Bot = null;
orderManager.IssueOrder(Order.Command("slot_open " + s.Index));
}
else
{
if (s.Bot == null && Map.Players[s.MapPlayer].AllowBots)
orderManager.IssueOrder(Order.Command("slot_bot {0} HackyAI".F(s.Index)));
else
orderManager.IssueOrder(Order.Command("slot_close " + s.Index));
}
return true;
};
}
} }
else else
{ {
@@ -330,6 +355,14 @@ namespace OpenRA.Widgets.Delegates
var status = template.GetWidget<CheckboxWidget>("STATUS"); var status = template.GetWidget<CheckboxWidget>("STATUS");
status.Checked = () => c.State == Session.ClientState.Ready; status.Checked = () => c.State == Session.ClientState.Ready;
status.OnMouseDown = CycleReady; status.OnMouseDown = CycleReady;
Session.Slot slot1 = slot;
color.IsVisible = () => !slot1.Spectator;
colorBlock.IsVisible = () => !slot1.Spectator;
faction.IsVisible = () => !slot1.Spectator;
factionname.IsVisible = () => !slot1.Spectator;
factionflag.IsVisible = () => !slot1.Spectator;
team.IsVisible = () => !slot1.Spectator;
} }
else else
{ {

View File

@@ -39,7 +39,7 @@ namespace OpenRA
public void AddPlayer(Player p) { players[p.Index] = p; } public void AddPlayer(Player p) { players[p.Index] = p; }
int localPlayerIndex; int localPlayerIndex = -999;
public Player LocalPlayer public Player LocalPlayer
{ {
get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; } get { return players.ContainsKey(localPlayerIndex) ? players[localPlayerIndex] : null; }

View File

@@ -103,6 +103,7 @@ namespace OpenRA
public static bool IsVisible(this Actor a, Player byPlayer) /* must never be relied on in synced code! */ public static bool IsVisible(this Actor a, Player byPlayer) /* must never be relied on in synced code! */
{ {
if (byPlayer == null) return true; // Observer
if (a.World.LocalPlayer != null && a.World.LocalPlayer.Shroud.Disabled) if (a.World.LocalPlayer != null && a.World.LocalPlayer.Shroud.Disabled)
return true; return true;

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA
// create the players which are bound through slots. // create the players which are bound through slots.
foreach (var slot in w.LobbyInfo.Slots) foreach (var slot in w.LobbyInfo.Slots)
{ {
var client = w.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index); var client = w.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index && slot.MapPlayer != null);
if (client != null) if (client != null)
{ {
/* spawn a real player in this slot. */ /* spawn a real player in this slot. */
@@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA
if (client.Index == Game.LocalClientId) if (client.Index == Game.LocalClientId)
w.SetLocalPlayer(player.Index); // bind this one to the local player. w.SetLocalPlayer(player.Index); // bind this one to the local player.
} }
else if (slot.Bot != null) else if (slot.Bot != null && slot.MapPlayer != null)
{ {
/* spawn a bot in this slot, "owned" by the host */ /* spawn a bot in this slot, "owned" by the host */
@@ -80,6 +80,14 @@ namespace OpenRA.Mods.RA
static Stance ChooseInitialStance(Player p, Player q) static Stance ChooseInitialStance(Player p, Player q)
{ {
if (p == q) return Stance.Ally; if (p == q) return Stance.Ally;
var pc = GetClientForPlayer(p);
var qc = GetClientForPlayer(q);
if (p.World.LobbyInfo.Slots.Count > 0)
{
if (p.World.LobbyInfo.Slots[pc.Slot].Spectator) return Stance.Ally;
if (p.World.LobbyInfo.Slots[qc.Slot].Spectator) return Stance.Ally;
}
if (p.PlayerRef.Allies.Contains(q.InternalName)) if (p.PlayerRef.Allies.Contains(q.InternalName))
return Stance.Ally; return Stance.Ally;
@@ -92,8 +100,6 @@ namespace OpenRA.Mods.RA
if (p.IsBot ^ q.IsBot) if (p.IsBot ^ q.IsBot)
return Stance.Enemy; // bots and humans hate each other return Stance.Enemy; // bots and humans hate each other
var pc = GetClientForPlayer(p);
var qc = GetClientForPlayer(q);
return pc.Team != 0 && pc.Team == qc.Team return pc.Team != 0 && pc.Team == qc.Team
? Stance.Ally : Stance.Enemy; ? Stance.Ally : Stance.Enemy;

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Network;
using OpenRA.Traits; using OpenRA.Traits;
using XRandom = OpenRA.Thirdparty.Random; using XRandom = OpenRA.Thirdparty.Random;
using OpenRA.FileFormats; using OpenRA.FileFormats;
@@ -232,6 +233,10 @@ namespace OpenRA.Mods.RA
return !hackyAI.enabled; return !hackyAI.enabled;
} }
bool HasHumanPlayers()
{
return p.World.players.Any(a => !a.Value.IsBot && !a.Value.NonCombatant);
}
int2? ChooseEnemyTarget() int2? ChooseEnemyTarget()
{ {
// Criteria for picking an enemy: // Criteria for picking an enemy:
@@ -240,7 +245,7 @@ namespace OpenRA.Mods.RA
// 3. not dead. // 3. not dead.
var possibleTargets = world.WorldActor.Trait<MPStartLocations>().Start var possibleTargets = world.WorldActor.Trait<MPStartLocations>().Start
.Where(kv => kv.Key != p && IsHumanPlayer(kv.Key) .Where(kv => kv.Key != p && (!HasHumanPlayers()|| IsHumanPlayer(kv.Key))
&& p.WinState == WinState.Undefined) && p.WinState == WinState.Undefined)
.Select(kv => kv.Value); .Select(kv => kv.Value);

View File

@@ -28,13 +28,15 @@ namespace OpenRA.Mods.RA
public void WorldLoaded(World world) public void WorldLoaded(World world)
{ {
var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0) var taken = world.LobbyInfo.Clients.Where(c => c.SpawnPoint != 0 && c.Slot != -1)
.Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList(); .Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList();
var available = world.Map.SpawnPoints.Except(taken).ToList(); var available = world.Map.SpawnPoints.Except(taken).ToList();
// Set spawn // Set spawn
foreach (var slot in world.LobbyInfo.Slots) foreach (var slot in world.LobbyInfo.Slots)
{ {
if (slot.Spectator)
continue; // Skip spectator slots
var client = world.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index); var client = world.LobbyInfo.Clients.FirstOrDefault(c => c.Slot == slot.Index);
var player = FindPlayerInSlot(world, slot); var player = FindPlayerInSlot(world, slot);
@@ -49,7 +51,7 @@ namespace OpenRA.Mods.RA
// Explore allied shroud // Explore allied shroud
foreach (var p in Start) foreach (var p in Start)
if (p.Key == world.LocalPlayer || p.Key.Stances[world.LocalPlayer] == Stance.Ally) if ((world.LocalPlayer != null ) &&(p.Key == world.LocalPlayer || p.Key.Stances[world.LocalPlayer] == Stance.Ally))
world.WorldActor.Trait<Shroud>().Explore(world, p.Value, world.WorldActor.Trait<Shroud>().Explore(world, p.Value,
world.WorldActor.Info.Traits.Get<MPStartLocationsInfo>().InitialExploreRange); world.WorldActor.Info.Traits.Get<MPStartLocationsInfo>().InitialExploreRange);

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion> <ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{4A8A43B5-A9EF-4ED0-99DD-4BAB10A0DB6E}</ProjectGuid> <ProjectGuid>{4A8A43B5-A9EF-4ED0-99DD-4BAB10A0DB6E}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
@@ -230,6 +230,7 @@
<Compile Include="WaterPaletteRotation.cs" /> <Compile Include="WaterPaletteRotation.cs" />
<Compile Include="Weapon.cs" /> <Compile Include="Weapon.cs" />
<Compile Include="Widgets\BuildPaletteWidget.cs" /> <Compile Include="Widgets\BuildPaletteWidget.cs" />
<Compile Include="Widgets\Delegates\IngameObserverChromeDelegate.cs" />
<Compile Include="Widgets\Delegates\IngameChromeDelegate.cs" /> <Compile Include="Widgets\Delegates\IngameChromeDelegate.cs" />
<Compile Include="Widgets\MoneyBinWidget.cs" /> <Compile Include="Widgets\MoneyBinWidget.cs" />
<Compile Include="Widgets\OrderButtonWidget.cs" /> <Compile Include="Widgets\OrderButtonWidget.cs" />

View File

@@ -14,8 +14,9 @@ namespace OpenRA.Mods.RA
{ {
public class OpenWidgetAtGameStartInfo : ITraitInfo public class OpenWidgetAtGameStartInfo : ITraitInfo
{ {
public readonly string Widget = "INGAME_ROOT"; public readonly string Widget = "INGAME_ROOT";
public readonly string ObserverWidget = "";
public object Create(ActorInitializer init) { return new OpenWidgetAtGameStart(this); } public object Create(ActorInitializer init) { return new OpenWidgetAtGameStart(this); }
} }
@@ -29,9 +30,10 @@ namespace OpenRA.Mods.RA
public void WorldLoaded(World world) public void WorldLoaded(World world)
{ {
// Todo: custom observer ui?
if (world.LocalPlayer != null) if (world.LocalPlayer != null)
world.OpenWindow(Info.Widget); world.OpenWindow(Info.Widget);
else if (Info.ObserverWidget != null)
world.OpenWindow(Info.ObserverWidget);
} }
} }
} }

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA
void SpawnUnitsForPlayer(Player p, int2 sp) void SpawnUnitsForPlayer(Player p, int2 sp)
{ {
if (!p.PlayerRef.DefaultStartingUnits) if (!p.PlayerRef.DefaultStartingUnits)
return; /* they don't want an mcv, the map provides something else for them. */ return; /* they don't want an mcv, the map provides something else for them OR it is a spectator. */
p.World.CreateActor("mcv", new TypeDictionary p.World.CreateActor("mcv", new TypeDictionary
{ {

View File

@@ -71,6 +71,8 @@ Player:
World: World:
OpenWidgetAtGameStart: OpenWidgetAtGameStart:
Widget: INGAME_ROOT
# ObserverWidget:
ScreenShaker: ScreenShaker:
NukePaletteEffect: NukePaletteEffect:
WaterPaletteRotation: WaterPaletteRotation:

View File

@@ -193,6 +193,7 @@
<image name="allies" x="30" y="84" width="30" height="15" /> <image name="allies" x="30" y="84" width="30" height="15" />
<image name="soviet" x="0" y="84" width="30" height="15" /> <image name="soviet" x="0" y="84" width="30" height="15" />
<image name="random" x="60" y="84" width="30" height="15" /> <image name="random" x="60" y="84" width="30" height="15" />
<image name="spectator" x="60" y="84" width="30" height="15" />
</collection> </collection>
<collection name="music" src="musicplayer.png"> <collection name="music" src="musicplayer.png">
<image name="pause" x="0" y="0" width="25" height="25" /> <image name="pause" x="0" y="0" width="25" height="25" />

View File

@@ -29,175 +29,204 @@ Background@SERVER_LOBBY:
Y:4 Y:4
Width:244 Width:244
Height:244 Height:244
Container@PLAYERS: ListBox@PLAYERSX:
Id:PLAYERS Id:PLAYERSX
X:20 X:20
Y:75 Y:75
Width:500 Width:500
Height:200 Height:227
Children: Children:
Container@TEMPLATE_LOCAL: Container@PLAYERS:
Id:TEMPLATE_LOCAL Id:PLAYERS
X:0 X:2
Y:0 Y:1
Width:500 Width:500
Height:30 Height:2270
Visible:false
Children: Children:
TextField@NAME: Container@TEMPLATE_LOCAL:
Id:NAME Id:TEMPLATE_LOCAL
Text:Name
Width:139
Height:25
X:0 X:0
Y:0 Y:0
MaxLength:16 Width:400
Button@COLOR: Height:30
Id:COLOR Visible:false
Width:65
Height:25
X:159
Y:0
Children: Children:
ColorBlock@COLORBLOCK: TextField@NAME:
Id:COLORBLOCK Id:NAME
X:5 Text:Name
Width:139
Height:25
X:0
Y:0
MaxLength:16
Button@COLOR:
Id:COLOR
Width:65
Height:25
X:159
Y:0
Children:
ColorBlock@COLORBLOCK:
Id:COLORBLOCK
X:5
Y:7
Width:PARENT_RIGHT-10
Height:PARENT_BOTTOM-12
Button@FACTION:
Id:FACTION
Width:110
Height:25
X:244
Y:0
Children:
Image@FACTIONFLAG:
Id:FACTIONFLAG
Width:30
Height:15
X:5
Y:5
Label@FACTIONNAME:
Id:FACTIONNAME
Text:Faction
Width:60
Height:25
X:40
Y:0
Button@TEAM:
Id:TEAM
Text:Team
Width:25
Height:25
X:374
Y:0
Checkbox@STATUS:
Id:STATUS
X:450
Y:2
Width:20
Height:20
Container@TEMPLATE_REMOTE:
Id:TEMPLATE_REMOTE
X:0
Y:0
Width:400
Height:30
Visible:false
Children:
Label@NAME:
Id:NAME
Text:Name
Width:139
Height:25
X:0
Y:0
ColorBlock@COLOR:
Id:COLOR
X:164
Y:7 Y:7
Width:PARENT_RIGHT-10 Width:55
Height:PARENT_BOTTOM-12 Height:13
Button@FACTION: Label@FACTION:
Id:FACTION Id:FACTION
Width:110 Width:110
Height:25
X:244
Y:0
Children:
Image@FACTIONFLAG:
Id:FACTIONFLAG
Width:30
Height:15
X:5
Y:5
Label@FACTIONNAME:
Id:FACTIONNAME
Text:Faction
Width:60
Height:25 Height:25
X:40 X:244
Y:0 Y:0
Button@TEAM: Children:
Id:TEAM Image@FACTIONFLAG:
Text:Team Id:FACTIONFLAG
Width:25 Width:30
Height:25 Height:15
X:374 X:5
Y:0 Y:5
Checkbox@STATUS: Label@FACTIONNAME:
Id:STATUS Id:FACTIONNAME
X:455 Text:Faction
Y:2 Width:60
Width:20 Height:25
Height:20 X:40
Container@TEMPLATE_REMOTE: Y:0
Id:TEMPLATE_REMOTE Label@TEAM:
X:0 Id:TEAM
Y:0 Text:Team
Width:500 Width:70
Height:30
Visible:false
Children:
Label@NAME:
Id:NAME
Text:Name
Width:139
Height:25
X:0
Y:0
ColorBlock@COLOR:
Id:COLOR
X:164
Y:7
Width:55
Height:13
Label@FACTION:
Id:FACTION
Width:110
Height:25
X:244
Y:0
Children:
Image@FACTIONFLAG:
Id:FACTIONFLAG
Width:30
Height:15
X:5
Y:5
Label@FACTIONNAME:
Id:FACTIONNAME
Text:Faction
Width:60
Height:25 Height:25
X:40 X:351
Y:0 Y:0
Label@TEAM: Align:Center
Id:TEAM Bold: false
Text:Team Checkbox@STATUS:
Width:70 Id:STATUS
Height:25 X:455
X:351 Y:2
Y:0 Width:20
Align:Center Height:20
Bold: false Container@TEMPLATE_EMPTY_SPECTATOR:
Checkbox@STATUS: Id:TEMPLATE_EMPTY_SPECTATOR
Id:STATUS
X:455
Y:2
Width:20
Height:20
Container@TEMPLATE_EMPTY:
Id:TEMPLATE_EMPTY
X:0
Y:0
Width:500
Height:30
Visible:false
Children:
Label@NAME:
Id:NAME
Text:Name
Width:139
Height:25
X:0 X:0
Y:0 Y:0
Button@JOIN: Width:400
Id:JOIN Height:30
Text:Play in this slot Visible:false
Width:PARENT_RIGHT - 160 Children:
Height:25 Button@NAME:
X:160 Id:NAME
Y:0 Text:Name
Container@TEMPLATE_EMPTY_HOST: Width:139
Id:TEMPLATE_EMPTY_HOST Height:25
X:0 X:0
Y:0 Y:0
Width:500 Button@JOIN:
Height:30 Id:JOIN
Visible:false Text:Spectate this match
Children: Width:PARENT_RIGHT - 90
Button@NAME: -- TODO: replace with dropdown Height:25
Id:NAME X:160
Text:Name Y:0
Width:155 Container@TEMPLATE_EMPTY:
Height:25 Id:TEMPLATE_EMPTY
X:0 X:0
Y:0 Y:0
Button@JOIN: Width:400
Id:JOIN Height:30
Text:Play in this slot Visible:false
Width:PARENT_RIGHT - 160 Children:
Height:25 Label@NAME:
X:160 Id:NAME
Text:Name
Width:139
Height:25
X:0
Y:0
Button@JOIN:
Id:JOIN
Text:Play in this slot
Width:PARENT_RIGHT - 90
Height:25
X:160
Y:0
Container@TEMPLATE_EMPTY_HOST:
Id:TEMPLATE_EMPTY_HOST
X:0
Y:0 Y:0
Width:400
Height:30
Visible:false
Children:
Button@NAME: -- TODO: replace with dropdown
Id:NAME
Text:Name
Width:155
Height:25
X:0
Y:0
Button@JOIN:
Id:JOIN
Text:Play in this slot
Width:PARENT_RIGHT - 90
Height:25
X:160
Y:0
Container@LABEL_CONTAINER: Container@LABEL_CONTAINER:
X:30 X:30
Y:45 Y:45
@@ -240,7 +269,7 @@ Background@SERVER_LOBBY:
Bold:True Bold:True
Label@LABEL_LOBBY_STATUS: Label@LABEL_LOBBY_STATUS:
Id:LABEL_LOBBY_STATUS Id:LABEL_LOBBY_STATUS
X:432 X:420
Y:0 Y:0
Width:70 Width:70
Height:25 Height:25

View File

@@ -284,3 +284,133 @@ Container@INGAME_ROOT:
Width:200 Width:200
Height:20 Height:20
Text: Give Exploration Text: Give Exploration
Container@OBSERVER_ROOT:
Id:OBSERVER_ROOT
Visible:true
Delegate:IngameObserverChromeDelegate
Children:
WorldInteractionController:
X:0
Y:0
Width:WINDOW_RIGHT
Height:WINDOW_BOTTOM
ViewportScrollController:
X:0
Y:0
Width:WINDOW_RIGHT
Height:WINDOW_BOTTOM
Timer@GAME_TIMER:
Id:GAME_TIMER
X: WINDOW_RIGHT/2
Y: 10
Background@POSTGAME_BG:
Id:POSTGAME_BG
X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:400
Height:100
Background:dialog4
Visible:false
Children:
Label@TEXT:
Id:TEXT
X:(PARENT_RIGHT - WIDTH)/2
Y:(PARENT_BOTTOM - HEIGHT)/2
Width:200
Height:40
Align:Center
Bold:True
SpecialPowerBin@INGAME_POWERS_BIN:
Id:INGAME_POWERS_BIN
X:0
Y:25
Button@INGAME_OPTIONS_BUTTON:
Id:INGAME_OPTIONS_BUTTON
X:0
Y:0
Width:160
Height:25
Text:Options
Bold:True
WorldTooltip:
Background@INGAME_OPTIONS_BG:
Id:INGAME_OPTIONS_BG
X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:300
Height:320
Visible:false
Children:
Label@LABEL_TITLE:
Id:LABEL_TITLE
X:(PARENT_RIGHT - WIDTH)/2
Y:20
Width:250
Height:25
Text:Options
Align:Center
Bold:True
Button@RESUME:
Id:RESUME
X:(PARENT_RIGHT - WIDTH)/2
Y:60
Width:160
Height:25
Text:Resume
Bold:True
Button@SETTINGS:
Id:SETTINGS
X:(PARENT_RIGHT - WIDTH)/2
Y:100
Width:160
Height:25
Text:Settings
Bold:True
Button@MUSIC:
Id:MUSIC
X:(PARENT_RIGHT - WIDTH)/2
Y:140
Width:160
Height:25
Text:Music
Bold:True
Button@SURRENDER:
Id:SURRENDER
X:(PARENT_RIGHT - WIDTH)/2
Y:180
Width:160
Height:25
Text:Surrender
Bold:True
Button@DISCONNECT:
Id:DISCONNECT
X:(PARENT_RIGHT - WIDTH)/2
Y:220
Width:160
Height:25
Text:Disconnect
Bold:True
Button@QUIT:
Id:QUIT
X:(PARENT_RIGHT - WIDTH)/2
Y:260
Width:160
Height:25
Text:Quit
Bold:True
ChatDisplay@CHAT_DISPLAY:
Id:CHAT_DISPLAY
X:250
Y:WINDOW_BOTTOM - HEIGHT - 30
Width: 760
Height: 200
ClickThrough: True
DrawBackground: False
RemoveTime:250
ChatEntry@CHAT_ENTRY:
Id:CHAT_ENTRY
X:250
Y:WINDOW_BOTTOM - HEIGHT
Width: 760
Height: 30
ClickThrough: True

View File

@@ -125,8 +125,10 @@ Player:
PlayerColorPalette: PlayerColorPalette:
BasePalette: terrain BasePalette: terrain
World: World:
OpenWidgetAtGameStart: OpenWidgetAtGameStart:
Widget: INGAME_ROOT
ObserverWidget: OBSERVER_ROOT
ScreenShaker: ScreenShaker:
WaterPaletteRotation: WaterPaletteRotation:
ChronoshiftPaletteEffect: ChronoshiftPaletteEffect: