Building hotkeys

This commit is contained in:
Boomer
2010-05-09 15:37:10 +02:00
committed by Chris Forbes
parent ac75259efd
commit bd72146548
7 changed files with 1909 additions and 1818 deletions

View File

@@ -1,254 +1,254 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA. * This file is part of OpenRA.
* *
* OpenRA is free software: you can redistribute it and/or modify * OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* OpenRA is distributed in the hope that it will be useful, * OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>. * along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/ */
#endregion #endregion
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Traits.Activities; using OpenRA.Traits.Activities;
namespace OpenRA namespace OpenRA
{ {
public class Actor public class Actor
{ {
[Sync] [Sync]
public readonly TypeDictionary traits = new TypeDictionary(); public readonly TypeDictionary traits = new TypeDictionary();
public readonly ActorInfo Info; public readonly ActorInfo Info;
public readonly World World; public readonly World World;
public readonly uint ActorID; public readonly uint ActorID;
[Sync] [Sync]
public int2 Location; public int2 Location;
[Sync] [Sync]
public Player Owner; public Player Owner;
[Sync] [Sync]
public int Health; public int Health;
IActivity currentActivity; IActivity currentActivity;
public Actor(World world, string name, int2 location, Player owner) public Actor(World world, string name, int2 location, Player owner)
{ {
World = world; World = world;
ActorID = world.NextAID(); ActorID = world.NextAID();
Location = location; Location = location;
CenterLocation = Traits.Util.CenterOfCell(Location); CenterLocation = Traits.Util.CenterOfCell(Location);
Owner = owner; Owner = owner;
if (name != null) if (name != null)
{ {
if (!Rules.Info.ContainsKey(name.ToLowerInvariant())) if (!Rules.Info.ContainsKey(name.ToLowerInvariant()))
throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant())); throw new NotImplementedException("No rules definition for unit {0}".F(name.ToLowerInvariant()));
Info = Rules.Info[name.ToLowerInvariant()]; Info = Rules.Info[name.ToLowerInvariant()];
Health = this.GetMaxHP(); Health = this.GetMaxHP();
foreach (var trait in Info.TraitsInConstructOrder()) foreach (var trait in Info.TraitsInConstructOrder())
traits.Add(trait.Create(this)); traits.Add(trait.Create(this));
} }
Size = Lazy.New(() => Size = Lazy.New(() =>
{ {
var si = Info.Traits.GetOrDefault<SelectableInfo>(); var si = Info.Traits.GetOrDefault<SelectableInfo>();
if (si != null && si.Bounds != null) if (si != null && si.Bounds != null)
return new float2(si.Bounds[0], si.Bounds[1]); return new float2(si.Bounds[0], si.Bounds[1]);
// auto size from render // auto size from render
var firstSprite = traits.WithInterface<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault(); var firstSprite = traits.WithInterface<IRender>().SelectMany(x => x.Render(this)).FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero; if (firstSprite.Sprite == null) return float2.Zero;
return firstSprite.Sprite.size; return firstSprite.Sprite.size;
}); });
} }
public void Tick() public void Tick()
{ {
var wasIdle = currentActivity is Idle; var wasIdle = currentActivity is Idle;
while (currentActivity != null) while (currentActivity != null)
{ {
var a = currentActivity; var a = currentActivity;
currentActivity = a.Tick(this) ?? new Idle(); currentActivity = a.Tick(this) ?? new Idle();
if (a == currentActivity) break; if (a == currentActivity) break;
if (currentActivity is Idle) if (currentActivity is Idle)
{ {
if (!wasIdle) if (!wasIdle)
foreach (var ni in traits.WithInterface<INotifyIdle>()) foreach (var ni in traits.WithInterface<INotifyIdle>())
ni.Idle(this); ni.Idle(this);
break; break;
} }
} }
} }
public bool IsIdle public bool IsIdle
{ {
get { return currentActivity == null || currentActivity is Idle; } get { return currentActivity == null || currentActivity is Idle; }
} }
public float2 CenterLocation; public float2 CenterLocation;
Lazy<float2> Size; OpenRA.FileFormats.Lazy<float2> Size;
public IEnumerable<Renderable> Render() public IEnumerable<Renderable> Render()
{ {
var mods = traits.WithInterface<IRenderModifier>(); var mods = traits.WithInterface<IRenderModifier>();
var sprites = traits.WithInterface<IRender>().SelectMany(x => x.Render(this)); var sprites = traits.WithInterface<IRender>().SelectMany(x => x.Render(this));
return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m)); return mods.Aggregate(sprites, (m, p) => p.ModifyRender(this, m));
} }
public Order Order( int2 xy, MouseInput mi ) public Order Order( int2 xy, MouseInput mi )
{ {
if (Owner != World.LocalPlayer) if (Owner != World.LocalPlayer)
return null; return null;
if (!World.Map.IsInMap(xy.X, xy.Y)) if (!World.Map.IsInMap(xy.X, xy.Y))
return null; return null;
var underCursor = World.FindUnitsAtMouse(mi.Location) var underCursor = World.FindUnitsAtMouse(mi.Location)
.Where(a => a.Info.Traits.Contains<SelectableInfo>()) .Where(a => a.Info.Traits.Contains<SelectableInfo>())
.OrderByDescending(a => a.Info.Traits.Get<SelectableInfo>().Priority) .OrderByDescending(a => a.Info.Traits.Get<SelectableInfo>().Priority)
.FirstOrDefault(); .FirstOrDefault();
return traits.WithInterface<IIssueOrder>() return traits.WithInterface<IIssueOrder>()
.Select( x => x.IssueOrder( this, xy, mi, underCursor ) ) .Select( x => x.IssueOrder( this, xy, mi, underCursor ) )
.FirstOrDefault( x => x != null ); .FirstOrDefault( x => x != null );
} }
public RectangleF GetBounds(bool useAltitude) public RectangleF GetBounds(bool useAltitude)
{ {
var si = Info.Traits.GetOrDefault<SelectableInfo>(); var si = Info.Traits.GetOrDefault<SelectableInfo>();
var size = Size.Value; var size = Size.Value;
var loc = CenterLocation - 0.5f * size; var loc = CenterLocation - 0.5f * size;
if (si != null && si.Bounds != null && si.Bounds.Length > 2) if (si != null && si.Bounds != null && si.Bounds.Length > 2)
loc += new float2(si.Bounds[2], si.Bounds[3]); loc += new float2(si.Bounds[2], si.Bounds[3]);
if (useAltitude) if (useAltitude)
{ {
var unit = traits.GetOrDefault<Unit>(); var unit = traits.GetOrDefault<Unit>();
if (unit != null) loc -= new float2(0, unit.Altitude); if (unit != null) loc -= new float2(0, unit.Altitude);
} }
return new RectangleF(loc.X, loc.Y, size.X, size.Y); return new RectangleF(loc.X, loc.Y, size.X, size.Y);
} }
public bool IsDead { get { return Health <= 0; } } public bool IsDead { get { return Health <= 0; } }
public bool IsInWorld { get; set; } public bool IsInWorld { get; set; }
public bool RemoveOnDeath = true; public bool RemoveOnDeath = true;
public DamageState GetDamageState() public DamageState GetDamageState()
{ {
if (Health <= 0) if (Health <= 0)
return DamageState.Dead; return DamageState.Dead;
if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow) if (Health < this.GetMaxHP() * World.Defaults.ConditionYellow)
return DamageState.Half; return DamageState.Half;
return DamageState.Normal; return DamageState.Normal;
} }
public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead) public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead)
{ {
if (IsDead) return; /* overkill! don't count extra hits as more kills! */ if (IsDead) return; /* overkill! don't count extra hits as more kills! */
var rawDamage = damage; var rawDamage = damage;
var oldState = GetDamageState(); var oldState = GetDamageState();
/* apply the damage modifiers, if we have any. */ /* apply the damage modifiers, if we have any. */
var modifier = (float)traits.WithInterface<IDamageModifier>() var modifier = (float)traits.WithInterface<IDamageModifier>()
.Select(t => t.GetDamageModifier()).Product(); .Select(t => t.GetDamageModifier()).Product();
damage = (int)(damage * modifier); damage = (int)(damage * modifier);
Health -= damage; Health -= damage;
if (Health <= 0) if (Health <= 0)
{ {
Health = 0; Health = 0;
attacker.Owner.Kills++; attacker.Owner.Kills++;
Owner.Deaths++; Owner.Deaths++;
if (RemoveOnDeath) if (RemoveOnDeath)
World.AddFrameEndTask(w => w.Remove(this)); World.AddFrameEndTask(w => w.Remove(this));
} }
var maxHP = this.GetMaxHP(); var maxHP = this.GetMaxHP();
if (Health > maxHP) Health = maxHP; if (Health > maxHP) Health = maxHP;
Log.Write("InflictDamage: {0} #{1} -> {2} #{3} raw={4} adj={5} hp={6} mod={7}", Log.Write("InflictDamage: {0} #{1} -> {2} #{3} raw={4} adj={5} hp={6} mod={7}",
attacker.Info.Name, attacker.ActorID, Info.Name, ActorID, rawDamage, damage, Health, modifier); attacker.Info.Name, attacker.ActorID, Info.Name, ActorID, rawDamage, damage, Health, modifier);
var newState = GetDamageState(); var newState = GetDamageState();
foreach (var nd in traits.WithInterface<INotifyDamage>()) foreach (var nd in traits.WithInterface<INotifyDamage>())
nd.Damaged(this, new AttackInfo nd.Damaged(this, new AttackInfo
{ {
Attacker = attacker, Attacker = attacker,
Damage = damage, Damage = damage,
DamageState = newState, DamageState = newState,
DamageStateChanged = newState != oldState, DamageStateChanged = newState != oldState,
Warhead = warhead Warhead = warhead
}); });
} }
public void QueueActivity( IActivity nextActivity ) public void QueueActivity( IActivity nextActivity )
{ {
if( currentActivity == null ) if( currentActivity == null )
{ {
currentActivity = nextActivity; currentActivity = nextActivity;
return; return;
} }
var act = currentActivity; var act = currentActivity;
while( act.NextActivity != null ) while( act.NextActivity != null )
{ {
act = act.NextActivity; act = act.NextActivity;
} }
act.NextActivity = nextActivity; act.NextActivity = nextActivity;
} }
public void CancelActivity() public void CancelActivity()
{ {
if( currentActivity != null ) if( currentActivity != null )
currentActivity.Cancel( this ); currentActivity.Cancel( this );
} }
// For pathdebug, et al // For pathdebug, et al
public IActivity GetCurrentActivity() public IActivity GetCurrentActivity()
{ {
return currentActivity; return currentActivity;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return (int)ActorID; return (int)ActorID;
} }
public override bool Equals( object obj ) public override bool Equals( object obj )
{ {
var o = obj as Actor; var o = obj as Actor;
return ( o != null && o.ActorID == ActorID ); return ( o != null && o.ActorID == ActorID );
} }
} }
} }

View File

@@ -33,6 +33,8 @@ using OpenRA.Network;
using OpenRA.Server; using OpenRA.Server;
using OpenRA.Support; using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Widgets;
using Timer = OpenRA.Support.Timer; using Timer = OpenRA.Support.Timer;
using XRandom = OpenRA.Thirdparty.Random; using XRandom = OpenRA.Thirdparty.Random;
@@ -47,7 +49,7 @@ namespace OpenRA
public static Controller controller; public static Controller controller;
internal static Chrome chrome; internal static Chrome chrome;
internal static UserSettings Settings; internal static UserSettings Settings;
internal static OrderManager orderManager; internal static OrderManager orderManager;
public static bool skipMakeAnims = true; public static bool skipMakeAnims = true;
@@ -69,12 +71,12 @@ namespace OpenRA
foreach (var dir in manifest.Folders) FileSystem.Mount(dir); foreach (var dir in manifest.Folders) FileSystem.Mount(dir);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg); foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
Timer.Time("mount temporary packages: {0}"); Timer.Time("mount temporary packages: {0}");
} }
public static void LoadModAssemblies(Manifest m) public static void LoadModAssemblies(Manifest m)
{ {
// All the core namespaces // All the core namespaces
var asms = typeof(Game).Assembly.GetNamespaces() var asms = typeof(Game).Assembly.GetNamespaces()
.Select(c => Pair.New(typeof(Game).Assembly, c)) .Select(c => Pair.New(typeof(Game).Assembly, c))
@@ -102,9 +104,9 @@ namespace OpenRA
throw new InvalidOperationException("Cannot locate type: {0}".F(classname)); throw new InvalidOperationException("Cannot locate type: {0}".F(classname));
} }
public static Dictionary<string,MapStub> AvailableMaps; public static Dictionary<string, MapStub> AvailableMaps;
// TODO: Do this nicer // TODO: Do this nicer
static Dictionary<string, MapStub> FindMaps(string[] mods) static Dictionary<string, MapStub> FindMaps(string[] mods)
{ {
@@ -118,48 +120,48 @@ namespace OpenRA
return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid); return paths.Select(p => new MapStub(new Folder(p))).ToDictionary(m => m.Uid);
} }
static void ChangeMods() static void ChangeMods()
{ {
Timer.Time( "----ChangeMods" ); Timer.Time("----ChangeMods");
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods); var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "manifest: {0}" ); Timer.Time("manifest: {0}");
LoadModAssemblies(manifest); LoadModAssemblies(manifest);
SheetBuilder.Initialize(renderer); SheetBuilder.Initialize(renderer);
LoadModPackages(manifest); LoadModPackages(manifest);
Timer.Time( "load assemblies, packages: {0}" ); Timer.Time("load assemblies, packages: {0}");
packageChangePending = false; packageChangePending = false;
} }
static void LoadMap(string mapName) static void LoadMap(string mapName)
{ {
Timer.Time( "----LoadMap" ); Timer.Time("----LoadMap");
SheetBuilder.Initialize(renderer); SheetBuilder.Initialize(renderer);
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods); var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "manifest: {0}" ); Timer.Time("manifest: {0}");
if (!Game.AvailableMaps.ContainsKey(mapName)) if (!Game.AvailableMaps.ContainsKey(mapName))
throw new InvalidDataException("Cannot find map with Uid {0}".F(mapName)); throw new InvalidDataException("Cannot find map with Uid {0}".F(mapName));
var map = new Map( Game.AvailableMaps[mapName].Package ); var map = new Map(Game.AvailableMaps[mapName].Package);
viewport = new Viewport(clientSize, map.TopLeft, map.BottomRight, renderer); viewport = new Viewport(clientSize, map.TopLeft, map.BottomRight, renderer);
world = null; // trying to access the old world will NRE, rather than silently doing it wrong. world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
ChromeProvider.Initialize(manifest.Chrome); ChromeProvider.Initialize(manifest.Chrome);
Timer.Time( "viewport, ChromeProvider: {0}" ); Timer.Time("viewport, ChromeProvider: {0}");
world = new World(manifest,map); world = new World(manifest, map);
Timer.Time( "world: {0}" ); Timer.Time("world: {0}");
SequenceProvider.Initialize(manifest.Sequences); SequenceProvider.Initialize(manifest.Sequences);
Timer.Time( "ChromeProv, SeqProv: {0}" ); Timer.Time("ChromeProv, SeqProv: {0}");
chrome = new Chrome(renderer, manifest); chrome = new Chrome(renderer, manifest);
Timer.Time( "chrome: {0}" ); Timer.Time("chrome: {0}");
Timer.Time( "----end LoadMap" ); Timer.Time("----end LoadMap");
Debug("Map change {0} -> {1}".F(Game.mapName, mapName)); Debug("Map change {0} -> {1}".F(Game.mapName, mapName));
} }
public static void MoveViewport(int2 loc) public static void MoveViewport(int2 loc)
{ {
viewport.Center(loc); viewport.Center(loc);
@@ -174,21 +176,21 @@ namespace OpenRA
CurrentHost = host; CurrentHost = host;
CurrentPort = port; CurrentPort = port;
orderManager = new OrderManager(new NetworkConnection( host, port ), ChooseReplayFilename()); orderManager = new OrderManager(new NetworkConnection(host, port), ChooseReplayFilename());
} }
static string ChooseReplayFilename() static string ChooseReplayFilename()
{ {
return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep"); return DateTime.UtcNow.ToString("OpenRA-yyyy-MM-ddThhmmssZ.rep");
} }
static void JoinLocal() static void JoinLocal()
{ {
if (orderManager != null) orderManager.Dispose(); if (orderManager != null) orderManager.Dispose();
orderManager = new OrderManager(new EchoConnection()); orderManager = new OrderManager(new EchoConnection());
} }
static int lastTime = Environment.TickCount; static int lastTime = Environment.TickCount;
static void ResetTimer() static void ResetTimer()
@@ -242,7 +244,7 @@ namespace OpenRA
return sb.ToString(); return sb.ToString();
} }
internal static void DumpSyncReport( int frame ) internal static void DumpSyncReport(int frame)
{ {
var f = syncReports.FirstOrDefault(a => a.First == frame); var f = syncReports.FirstOrDefault(a => a.First == frame);
if (f == null) if (f == null)
@@ -262,11 +264,11 @@ namespace OpenRA
// TODO: Only do this on mod change // TODO: Only do this on mod change
Timer.Time("----begin maplist"); Timer.Time("----begin maplist");
AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods); AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "maplist: {0}" ); Timer.Time("maplist: {0}");
ChangeMods(); ChangeMods();
return; return;
} }
if (mapChangePending) if (mapChangePending)
{ {
mapName = LobbyInfo.GlobalSettings.Map; mapName = LobbyInfo.GlobalSettings.Map;
@@ -281,9 +283,9 @@ namespace OpenRA
using (new PerfSample("tick_time")) using (new PerfSample("tick_time"))
{ {
lastTime += Settings.Timestep; lastTime += Settings.Timestep;
chrome.Tick( world ); chrome.Tick(world);
orderManager.TickImmediate( world ); orderManager.TickImmediate(world);
var isNetTick = LocalTick % NetTickScale == 0; var isNetTick = LocalTick % NetTickScale == 0;
@@ -309,7 +311,7 @@ namespace OpenRA
using (new PerfSample("render")) using (new PerfSample("render"))
{ {
++RenderFrame; ++RenderFrame;
viewport.DrawRegions( world ); viewport.DrawRegions(world);
} }
PerfHistory.items["render"].Tick(); PerfHistory.items["render"].Tick();
@@ -364,7 +366,7 @@ namespace OpenRA
if (mapName != LobbyInfo.GlobalSettings.Map) if (mapName != LobbyInfo.GlobalSettings.Map)
mapChangePending = true; mapChangePending = true;
if (string.Join(",", oldLobbyInfo.GlobalSettings.Mods) if (string.Join(",", oldLobbyInfo.GlobalSettings.Mods)
!= string.Join(",", LobbyInfo.GlobalSettings.Mods)) != string.Join(",", LobbyInfo.GlobalSettings.Mods))
{ {
@@ -379,18 +381,18 @@ namespace OpenRA
static void LoadShellMap(string map) static void LoadShellMap(string map)
{ {
LoadMap(map); LoadMap(map);
world.Queries = new World.AllQueries(world); world.Queries = new World.AllQueries(world);
foreach (var p in world.players.Values) foreach (var p in world.players.Values)
foreach (var q in world.players.Values) foreach (var q in world.players.Values)
p.Stances[q] = ChooseInitialStance(p, q); p.Stances[q] = ChooseInitialStance(p, q);
foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>()) foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>())
gs.GameStarted(world); gs.GameStarted(world);
orderManager.StartGame(); orderManager.StartGame();
} }
internal static void StartGame() internal static void StartGame()
{ {
LoadMap(LobbyInfo.GlobalSettings.Map); LoadMap(LobbyInfo.GlobalSettings.Map);
@@ -405,13 +407,13 @@ namespace OpenRA
foreach (var p in world.players.Values) foreach (var p in world.players.Values)
foreach (var q in world.players.Values) foreach (var q in world.players.Values)
p.Stances[q] = ChooseInitialStance(p, q); p.Stances[q] = ChooseInitialStance(p, q);
world.Queries = new World.AllQueries(world); world.Queries = new World.AllQueries(world);
foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>()) foreach (var gs in world.WorldActor.traits.WithInterface<IGameStarted>())
gs.GameStarted(world); gs.GameStarted(world);
viewport.GoToStartLocation( world.LocalPlayer ); viewport.GoToStartLocation(world.LocalPlayer);
orderManager.StartGame(); orderManager.StartGame();
} }
@@ -423,7 +425,7 @@ namespace OpenRA
var pc = GetClientForPlayer(p); var pc = GetClientForPlayer(p);
var qc = GetClientForPlayer(q); 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;
} }
@@ -441,8 +443,8 @@ namespace OpenRA
if (ev == MouseInputEvent.Down) if (ev == MouseInputEvent.Down)
lastPos = new int2(e.Location); lastPos = new int2(e.Location);
if (ev == MouseInputEvent.Move && if (ev == MouseInputEvent.Move &&
(e.Button == MouseButtons.Middle || (e.Button == MouseButtons.Middle ||
e.Button == (MouseButtons.Left | MouseButtons.Right))) e.Button == (MouseButtons.Left | MouseButtons.Right)))
{ {
var p = new int2(e.Location); var p = new int2(e.Location);
@@ -450,7 +452,7 @@ namespace OpenRA
lastPos = p; lastPos = p;
} }
viewport.DispatchMouseInput( world, viewport.DispatchMouseInput(world,
new MouseInput new MouseInput
{ {
Button = (MouseButton)(int)e.Button, Button = (MouseButton)(int)e.Button,
@@ -459,8 +461,8 @@ namespace OpenRA
Modifiers = modifierKeys, Modifiers = modifierKeys,
}); });
if( sync != world.SyncHash() && world == initialWorld ) if (sync != world.SyncHash() && world == initialWorld)
throw new InvalidOperationException( "Desync in DispatchMouseInput" ); throw new InvalidOperationException("Desync in DispatchMouseInput");
} }
internal static bool IsHost internal static bool IsHost
@@ -487,11 +489,11 @@ namespace OpenRA
{ ')', '0' }, { ')', '0' },
}; };
public static void HandleKeyPress( KeyPressEventArgs e, Modifiers modifiers ) public static void HandleKeyPress(KeyPressEventArgs e, Modifiers modifiers)
{ {
int sync = world.SyncHash(); int sync = world.SyncHash();
if( e.KeyChar == '\r' ) if (e.KeyChar == '\r')
chat.Toggle(); chat.Toggle();
else if (Game.chat.isChatting) else if (Game.chat.isChatting)
chat.TypeChar(e.KeyChar); chat.TypeChar(e.KeyChar);
@@ -503,12 +505,17 @@ namespace OpenRA
Game.controller.selection.DoControlGroup(world, Game.controller.selection.DoControlGroup(world,
c - '0', modifiers); c - '0', modifiers);
if (c == 'h') if (c == 08)
Game.controller.GotoNextBase(); Game.controller.GotoNextBase();
if (c == 09)
BuildPaletteWidget.TabChange((Control.ModifierKeys & Keys.Shift) == Keys.Shift ? true : false);
BuildPaletteWidget.DoBuildingHotkey(c, world);
} }
if( sync != Game.world.SyncHash() ) if (sync != Game.world.SyncHash())
throw new InvalidOperationException( "Desync in OnKeyPress" ); throw new InvalidOperationException("Desync in OnKeyPress");
} }
public static void HandleModifierKeys(Modifiers mods) public static void HandleModifierKeys(Modifiers mods)
@@ -539,15 +546,15 @@ namespace OpenRA
throw new InvalidOperationException("Unable to find game root."); throw new InvalidOperationException("Unable to find game root.");
Directory.SetCurrentDirectory(".."); Directory.SetCurrentDirectory("..");
} }
LoadUserSettings(settings); LoadUserSettings(settings);
LobbyInfo.GlobalSettings.Mods = Settings.InitialMods; LobbyInfo.GlobalSettings.Mods = Settings.InitialMods;
// Load the default mod to access required files // Load the default mod to access required files
LoadModPackages(new Manifest(LobbyInfo.GlobalSettings.Mods)); LoadModPackages(new Manifest(LobbyInfo.GlobalSettings.Mods));
Renderer.SheetSize = Settings.SheetSize; Renderer.SheetSize = Settings.SheetSize;
bool windowed = !Game.Settings.Fullscreen; bool windowed = !Game.Settings.Fullscreen;
var resolution = GetResolution(settings); var resolution = GetResolution(settings);
renderer = new Renderer(resolution, windowed); renderer = new Renderer(resolution, windowed);
@@ -555,21 +562,21 @@ namespace OpenRA
controller = new Controller(); controller = new Controller();
clientSize = new int2(resolution); clientSize = new int2(resolution);
Sound.Initialize(); Sound.Initialize();
PerfHistory.items["render"].hasNormalTick = false; PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false; PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["text"].hasNormalTick = false; PerfHistory.items["text"].hasNormalTick = false;
PerfHistory.items["cursor"].hasNormalTick = false; PerfHistory.items["cursor"].hasNormalTick = false;
AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods); AvailableMaps = FindMaps(LobbyInfo.GlobalSettings.Mods);
ChangeMods(); ChangeMods();
if( Settings.Replay != "" ) if (Settings.Replay != "")
orderManager = new OrderManager( new ReplayConnection( Settings.Replay ) ); orderManager = new OrderManager(new ReplayConnection(Settings.Replay));
else else
JoinLocal(); JoinLocal();
LoadShellMap(new Manifest(LobbyInfo.GlobalSettings.Mods).ShellmapUid); LoadShellMap(new Manifest(LobbyInfo.GlobalSettings.Mods).ShellmapUid);
ResetTimer(); ResetTimer();

View File

@@ -1,198 +1,198 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA. * This file is part of OpenRA.
* *
* OpenRA is free software: you can redistribute it and/or modify * OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* OpenRA is distributed in the hope that it will be useful, * OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>. * along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/ */
#endregion #endregion
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA namespace OpenRA
{ {
public enum PowerState { Normal, Low, Critical }; public enum PowerState { Normal, Low, Critical };
public class Player public class Player
{ {
public Actor PlayerActor; public Actor PlayerActor;
public int Kills; public int Kills;
public int Deaths; public int Deaths;
public readonly string Palette; public readonly string Palette;
public readonly Color Color; public readonly Color Color;
public readonly string PlayerName; public readonly string PlayerName;
public readonly string InternalName; public readonly string InternalName;
public readonly CountryInfo Country; public readonly CountryInfo Country;
public readonly int Index; public readonly int Index;
public int Cash = 10000; public int Cash = 10000;
public int Ore = 0; public int Ore = 0;
public int OreCapacity; public int OreCapacity;
public int DisplayCash = 0; public int DisplayCash = 0;
public int PowerProvided = 0; public int PowerProvided = 0;
public int PowerDrained = 0; public int PowerDrained = 0;
public ShroudRenderer Shroud; public ShroudRenderer Shroud;
public World World { get; private set; } public World World { get; private set; }
public static List<Tuple<string, string, Color>> PlayerColors( World world ) public static List<OpenRA.FileFormats.Tuple<string, string, Color>> PlayerColors(World world)
{ {
return world.WorldActor.Info.Traits.WithInterface<PlayerColorPaletteInfo>() return world.WorldActor.Info.Traits.WithInterface<PlayerColorPaletteInfo>()
.Where(p => p.Playable) .Where(p => p.Playable)
.Select(p => Tuple.New(p.Name, p.DisplayName, p.Color)) .Select(p => OpenRA.FileFormats.Tuple.New(p.Name, p.DisplayName, p.Color))
.ToList(); .ToList();
} }
public Player( World world, Session.Client client ) public Player( World world, Session.Client client )
{ {
World = world; World = world;
Shroud = new ShroudRenderer(this, world.Map); Shroud = new ShroudRenderer(this, world.Map);
PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this); PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
if (client != null) if (client != null)
{ {
Index = client.Index; Index = client.Index;
Palette = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].a; Palette = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].a;
Color = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].c; Color = PlayerColors(world)[client.PaletteIndex % PlayerColors(world).Count()].c;
PlayerName = client.Name; PlayerName = client.Name;
InternalName = "Multi{0}".F(client.Index); InternalName = "Multi{0}".F(client.Index);
} }
else else
{ {
Index = -1; Index = -1;
PlayerName = InternalName = "Neutral"; PlayerName = InternalName = "Neutral";
Palette = "neutral"; Palette = "neutral";
Color = Color.Gray; // HACK HACK Color = Color.Gray; // HACK HACK
} }
Country = world.GetCountries() Country = world.GetCountries()
.FirstOrDefault(c => client != null && client.Country == c.Name) .FirstOrDefault(c => client != null && client.Country == c.Name)
?? world.GetCountries().Random(world.SharedRandom); ?? world.GetCountries().Random(world.SharedRandom);
} }
void UpdatePower() void UpdatePower()
{ {
var oldBalance = PowerProvided - PowerDrained; var oldBalance = PowerProvided - PowerDrained;
PowerProvided = 0; PowerProvided = 0;
PowerDrained = 0; PowerDrained = 0;
var myBuildings = World.Queries.OwnedBy[this] var myBuildings = World.Queries.OwnedBy[this]
.WithTrait<Building>(); .WithTrait<Building>();
foreach (var a in myBuildings) foreach (var a in myBuildings)
{ {
var p = a.Trait.GetPowerUsage(); var p = a.Trait.GetPowerUsage();
if (p > 0) if (p > 0)
PowerProvided += p; PowerProvided += p;
else else
PowerDrained -= p; PowerDrained -= p;
} }
if (PowerProvided - PowerDrained < 0) if (PowerProvided - PowerDrained < 0)
if (PowerProvided - PowerDrained != oldBalance) if (PowerProvided - PowerDrained != oldBalance)
GiveAdvice(World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().LowPower); GiveAdvice(World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().LowPower);
} }
public float GetSiloFullness() public float GetSiloFullness()
{ {
return (float)Ore / OreCapacity; return (float)Ore / OreCapacity;
} }
public PowerState GetPowerState() public PowerState GetPowerState()
{ {
if (PowerProvided >= PowerDrained) return PowerState.Normal; if (PowerProvided >= PowerDrained) return PowerState.Normal;
if (PowerProvided > PowerDrained / 2) return PowerState.Low; if (PowerProvided > PowerDrained / 2) return PowerState.Low;
return PowerState.Critical; return PowerState.Critical;
} }
void UpdateOreCapacity() void UpdateOreCapacity()
{ {
OreCapacity = World.Queries.OwnedBy[this] OreCapacity = World.Queries.OwnedBy[this]
.Where(a => a.traits.Contains<StoresOre>()) .Where(a => a.traits.Contains<StoresOre>())
.Select(a => a.Info.Traits.Get<StoresOreInfo>()) .Select(a => a.Info.Traits.Get<StoresOreInfo>())
.Sum(b => b.Capacity); .Sum(b => b.Capacity);
} }
void GiveAdvice(string advice) void GiveAdvice(string advice)
{ {
// todo: store the condition or something. // todo: store the condition or something.
// repeat after World.Defaults.SpeakDelay, as long as the condition holds. // repeat after World.Defaults.SpeakDelay, as long as the condition holds.
Sound.PlayToPlayer(this, advice); Sound.PlayToPlayer(this, advice);
} }
public void GiveCash( int num ) { Cash += num; } public void GiveCash( int num ) { Cash += num; }
public void GiveOre(int num) public void GiveOre(int num)
{ {
Ore += num; Ore += num;
if (Ore > OreCapacity) if (Ore > OreCapacity)
Ore = OreCapacity; // trim off the overflow. Ore = OreCapacity; // trim off the overflow.
if (Ore > .8 * OreCapacity) if (Ore > .8 * OreCapacity)
GiveAdvice(World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().SilosNeeded); GiveAdvice(World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().SilosNeeded);
} }
public bool TakeCash( int num ) public bool TakeCash( int num )
{ {
if (Cash + Ore < num) return false; if (Cash + Ore < num) return false;
if (Ore <= num) if (Ore <= num)
{ {
num -= Ore; num -= Ore;
Ore = 0; Ore = 0;
Cash -= num; Cash -= num;
} }
else else
Ore -= num; Ore -= num;
return true; return true;
} }
const float displayCashFracPerFrame = .07f; const float displayCashFracPerFrame = .07f;
const int displayCashDeltaPerFrame = 37; const int displayCashDeltaPerFrame = 37;
public void Tick() public void Tick()
{ {
UpdatePower(); UpdatePower();
UpdateOreCapacity(); UpdateOreCapacity();
var totalMoney = Cash + Ore; var totalMoney = Cash + Ore;
var diff = Math.Abs(totalMoney - DisplayCash); var diff = Math.Abs(totalMoney - DisplayCash);
var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame), var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame),
displayCashDeltaPerFrame), diff); displayCashDeltaPerFrame), diff);
var eva = World.WorldActor.Info.Traits.Get<EvaAlertsInfo>(); var eva = World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
if (DisplayCash < totalMoney) if (DisplayCash < totalMoney)
{ {
DisplayCash += move; DisplayCash += move;
Sound.PlayToPlayer(this, eva.CashTickUp); Sound.PlayToPlayer(this, eva.CashTickUp);
} }
else if (DisplayCash > totalMoney) else if (DisplayCash > totalMoney)
{ {
DisplayCash -= move; DisplayCash -= move;
Sound.PlayToPlayer(this, eva.CashTickDown); Sound.PlayToPlayer(this, eva.CashTickDown);
} }
} }
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>(); public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
} }
} }

View File

@@ -1,48 +1,49 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA. * This file is part of OpenRA.
* *
* OpenRA is free software: you can redistribute it and/or modify * OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* OpenRA is distributed in the hope that it will be useful, * OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>. * along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/ */
#endregion #endregion
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
class ValuedInfo : ITraitInfo class ValuedInfo : ITraitInfo
{ {
public readonly int Cost = 0; public readonly int Cost = 0;
public readonly string Description = ""; public readonly string Description = "";
public readonly string LongDesc = ""; public readonly string LongDesc = "";
public virtual object Create(Actor self) { return new Valued(); } public virtual object Create(Actor self) { return new Valued(); }
} }
class BuildableInfo : ValuedInfo class BuildableInfo : ValuedInfo
{ {
public readonly int TechLevel = -1; public readonly int TechLevel = -1;
public readonly string[] Prerequisites = { }; public readonly string[] Prerequisites = { };
public readonly string[] BuiltAt = { }; public readonly string[] BuiltAt = { };
public readonly string[] Owner = { }; public readonly string[] Owner = { };
public readonly string Icon = null; public readonly string Icon = null;
public readonly string[] AlternateName = { }; public readonly string[] AlternateName = { };
public readonly int BuildPaletteOrder = 50; public readonly int BuildPaletteOrder = 50;
public readonly string Hotkey = null;
public override object Create(Actor self) { return new Buildable(); }
} public override object Create(Actor self) { return new Buildable(); }
}
class Valued { } /* halfway to buildable */
class Buildable { } class Valued { } /* halfway to buildable */
} class Buildable { }
}

View File

@@ -1,72 +1,72 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA. * This file is part of OpenRA.
* *
* OpenRA is free software: you can redistribute it and/or modify * OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* OpenRA is distributed in the hope that it will be useful, * OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>. * along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/ */
#endregion #endregion
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
class ScreenShakerInfo : ITraitInfo class ScreenShakerInfo : ITraitInfo
{ {
public object Create( Actor self ) { return new ScreenShaker(); } public object Create( Actor self ) { return new ScreenShaker(); }
} }
public class ScreenShaker : ITick public class ScreenShaker : ITick
{ {
int ticks = 0; int ticks = 0;
List<Tuple<int, float2, int>> shakeEffects = new List<Tuple<int, float2, int>>(); List<OpenRA.FileFormats.Tuple<int, float2, int>> shakeEffects = new List<OpenRA.FileFormats.Tuple<int, float2, int>>();
public void Tick (Actor self) public void Tick (Actor self)
{ {
Game.viewport.Scroll(getScrollOffset()); Game.viewport.Scroll(getScrollOffset());
shakeEffects.RemoveAll(t => t.a == ticks); shakeEffects.RemoveAll(t => t.a == ticks);
ticks++; ticks++;
} }
public void AddEffect(int time, float2 position, int intensity) public void AddEffect(int time, float2 position, int intensity)
{ {
shakeEffects.Add(Tuple.New(ticks + time, position, intensity)); shakeEffects.Add(OpenRA.FileFormats.Tuple.New(ticks + time, position, intensity));
} }
public float2 getScrollOffset() public float2 getScrollOffset()
{ {
int xFreq = 4; int xFreq = 4;
int yFreq = 5; int yFreq = 5;
return GetIntensity() * new float2( return GetIntensity() * new float2(
(float) Math.Sin((ticks*2*Math.PI)/xFreq) , (float) Math.Sin((ticks*2*Math.PI)/xFreq) ,
(float) Math.Cos((ticks*2*Math.PI)/yFreq)); (float) Math.Cos((ticks*2*Math.PI)/yFreq));
} }
public float GetIntensity() public float GetIntensity()
{ {
var cp = Game.viewport.Location var cp = Game.viewport.Location
+ .5f * new float2(Game.viewport.Width, Game.viewport.Height); + .5f * new float2(Game.viewport.Width, Game.viewport.Height);
var intensity = 24 * 24 * 100 * shakeEffects.Sum( var intensity = 24 * 24 * 100 * shakeEffects.Sum(
e => e.c / (e.b - cp).LengthSquared); e => e.c / (e.b - cp).LengthSquared);
return Math.Min(intensity, 10); return Math.Min(intensity, 10);
} }
} }
} }

View File

@@ -1,95 +1,95 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA. * This file is part of OpenRA.
* *
* OpenRA is free software: you can redistribute it and/or modify * OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* OpenRA is distributed in the hope that it will be useful, * OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>. * along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/ */
#endregion #endregion
using System.Drawing; using System.Drawing;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA; using OpenRA;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Orders; using OpenRA.Orders;
using System; using System;
namespace OpenRA.Widgets namespace OpenRA.Widgets
{ {
class BuildPaletteWidget : Widget class BuildPaletteWidget : Widget
{ {
public int Columns = 3; public int Columns = 3;
public int Rows = 5; public int Rows = 5;
string currentTab = "Building"; string currentTab = "Building";
bool paletteOpen = false; bool paletteOpen = false;
Dictionary<string, string[]> tabImageNames; Dictionary<string, string[]> tabImageNames;
Dictionary<string, Sprite> tabSprites; Dictionary<string, Sprite> tabSprites;
static float2 paletteOpenOrigin = new float2(Game.viewport.Width - 215, 280); static float2 paletteOpenOrigin = new float2(Game.viewport.Width - 215, 280);
static float2 paletteClosedOrigin = new float2(Game.viewport.Width - 16, 280); static float2 paletteClosedOrigin = new float2(Game.viewport.Width - 16, 280);
static float2 paletteOrigin = paletteClosedOrigin; static float2 paletteOrigin = paletteClosedOrigin;
const int paletteAnimationLength = 7; const int paletteAnimationLength = 7;
int paletteAnimationFrame = 0; int paletteAnimationFrame = 0;
bool paletteAnimating = false; bool paletteAnimating = false;
List<Pair<Rectangle, Action<MouseInput>>> buttons = new List<Pair<Rectangle,Action<MouseInput>>>(); List<Pair<Rectangle, Action<MouseInput>>> buttons = new List<Pair<Rectangle,Action<MouseInput>>>();
Animation cantBuild; Animation cantBuild;
Animation ready; Animation ready;
Animation clock; Animation clock;
List<string> visibleTabs = new List<string>(); List<string> visibleTabs = new List<string>();
public BuildPaletteWidget() : base() { } public BuildPaletteWidget() : base() { }
public BuildPaletteWidget(Widget other) public BuildPaletteWidget(Widget other)
: base(other) : base(other)
{ {
throw new NotImplementedException("Why are you Cloning BuildPalette?"); throw new NotImplementedException("Why are you Cloning BuildPalette?");
} }
public override Widget Clone() { return new BuildPaletteWidget(this); } public override Widget Clone() { return new BuildPaletteWidget(this); }
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
cantBuild = new Animation("clock"); cantBuild = new Animation("clock");
cantBuild.PlayFetchIndex("idle", () => 0); cantBuild.PlayFetchIndex("idle", () => 0);
ready = new Animation("pips"); ready = new Animation("pips");
ready.PlayRepeating("ready"); ready.PlayRepeating("ready");
clock = new Animation("clock"); clock = new Animation("clock");
tabSprites = Rules.Info.Values tabSprites = Rules.Info.Values
.Where(u => u.Traits.Contains<BuildableInfo>()) .Where(u => u.Traits.Contains<BuildableInfo>())
.ToDictionary( .ToDictionary(
u => u.Name, u => u.Name,
u => SpriteSheetBuilder.LoadAllSprites(u.Traits.Get<BuildableInfo>().Icon ?? (u.Name + "icon"))[0]); u => SpriteSheetBuilder.LoadAllSprites(u.Traits.Get<BuildableInfo>().Icon ?? (u.Name + "icon"))[0]);
var groups = Rules.Categories(); var groups = Rules.Categories();
tabImageNames = groups.Select( tabImageNames = groups.Select(
(g, i) => Pair.New(g, (g, i) => Pair.New(g,
OpenRA.Graphics.Util.MakeArray(3, OpenRA.Graphics.Util.MakeArray(3,
n => i.ToString()))) n => i.ToString())))
.ToDictionary(a => a.First, a => a.Second); .ToDictionary(a => a.First, a => a.Second);
} }
public override void Tick(World world) public override void Tick(World world)
{ {
visibleTabs.Clear(); visibleTabs.Clear();
foreach (var q in tabImageNames) foreach (var q in tabImageNames)
if (!Rules.TechTree.BuildableItems(world.LocalPlayer, q.Key).Any()) if (!Rules.TechTree.BuildableItems(world.LocalPlayer, q.Key).Any())
{ {
@@ -97,84 +97,84 @@ namespace OpenRA.Widgets
currentTab = null; currentTab = null;
} }
else else
visibleTabs.Add(q.Key); visibleTabs.Add(q.Key);
if (currentTab == null) if (currentTab == null)
currentTab = visibleTabs.FirstOrDefault(); currentTab = visibleTabs.FirstOrDefault();
TickPaletteAnimation(world); TickPaletteAnimation(world);
base.Tick(world); base.Tick(world);
} }
void TickPaletteAnimation(World world) void TickPaletteAnimation(World world)
{ {
if (!paletteAnimating) if (!paletteAnimating)
return; return;
// Increment frame // Increment frame
if (paletteOpen) if (paletteOpen)
paletteAnimationFrame++; paletteAnimationFrame++;
else else
paletteAnimationFrame--; paletteAnimationFrame--;
// Calculate palette position // Calculate palette position
if (paletteAnimationFrame <= paletteAnimationLength) if (paletteAnimationFrame <= paletteAnimationLength)
paletteOrigin = float2.Lerp(paletteClosedOrigin, paletteOpenOrigin, paletteAnimationFrame * 1.0f / paletteAnimationLength); paletteOrigin = float2.Lerp(paletteClosedOrigin, paletteOpenOrigin, paletteAnimationFrame * 1.0f / paletteAnimationLength);
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>(); var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
// Play palette-open sound at the start of the activate anim (open) // Play palette-open sound at the start of the activate anim (open)
if (paletteAnimationFrame == 1 && paletteOpen) if (paletteAnimationFrame == 1 && paletteOpen)
Sound.Play(eva.BuildPaletteOpen); Sound.Play(eva.BuildPaletteOpen);
// Play palette-close sound at the start of the activate anim (close) // Play palette-close sound at the start of the activate anim (close)
if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen) if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen)
Sound.Play(eva.BuildPaletteClose); Sound.Play(eva.BuildPaletteClose);
// Animation is complete // Animation is complete
if ((paletteAnimationFrame == 0 && !paletteOpen) if ((paletteAnimationFrame == 0 && !paletteOpen)
|| (paletteAnimationFrame == paletteAnimationLength && paletteOpen)) || (paletteAnimationFrame == paletteAnimationLength && paletteOpen))
{ {
paletteAnimating = false; paletteAnimating = false;
} }
} }
public void SetCurrentTab(string produces) public void SetCurrentTab(string produces)
{ {
if (!paletteOpen) if (!paletteOpen)
paletteAnimating = true; paletteAnimating = true;
paletteOpen = true; paletteOpen = true;
currentTab = produces; currentTab = produces;
} }
public override bool HandleInput(MouseInput mi) public override bool HandleInput(MouseInput mi)
{ {
// Are we able to handle this event? // Are we able to handle this event?
if (!IsVisible() || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y)) if (!IsVisible() || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y))
return base.HandleInput(mi); return base.HandleInput(mi);
if (base.HandleInput(mi)) if (base.HandleInput(mi))
return true; return true;
if (mi.Event == MouseInputEvent.Down) if (mi.Event == MouseInputEvent.Down)
{ {
var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint())) var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint()))
.Select(a => a.Second).FirstOrDefault(); .Select(a => a.Second).FirstOrDefault();
if (action == null) if (action == null)
return false; return false;
action(mi); action(mi);
return true; return true;
} }
return false; return false;
} }
public override void Draw (World world) public override void Draw (World world)
{ {
int paletteHeight = DrawPalette(world, currentTab); int paletteHeight = DrawPalette(world, currentTab);
DrawBuildTabs(world, paletteHeight); DrawBuildTabs(world, paletteHeight);
} }
int DrawPalette(World world, string queueName) int DrawPalette(World world, string queueName)
@@ -307,98 +307,107 @@ namespace OpenRA.Widgets
Game.chrome.renderer.RgbaSpriteRenderer.Flush(); Game.chrome.renderer.RgbaSpriteRenderer.Flush();
return 48 * y + 9; return 48 * y + 9;
} }
Action<MouseInput> HandleClick(string name, World world) Action<MouseInput> HandleClick(string name, World world)
{ {
return mi => { return mi => {
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>(); var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.TabClick); Sound.Play(eva.TabClick);
if (name != null) if (name != null)
HandleBuildPalette(world, name, (mi.Button == MouseButton.Left)); HandleBuildPalette(world, name, (mi.Button == MouseButton.Left));
}; };
} }
Action<MouseInput> HandleTabClick(string button, World world) static void Hotkey(World world, String name)
{ {
return mi => { var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
if (mi.Button != MouseButton.Left) Sound.Play(eva.TabClick);
return;
if (name != null)
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>(); HandleBuildPalette(world, name, true);
Sound.Play(eva.TabClick); }
var wasOpen = paletteOpen;
paletteOpen = (currentTab == button && wasOpen) ? false : true; Action<MouseInput> HandleTabClick(string button, World world)
currentTab = button; {
if (wasOpen != paletteOpen) return mi => {
paletteAnimating = true; if (mi.Button != MouseButton.Left)
}; return;
}
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
static string Description( string a ) Sound.Play(eva.TabClick);
{ var wasOpen = paletteOpen;
if( a[ 0 ] == '@' ) paletteOpen = (currentTab == button && wasOpen) ? false : true;
return "any " + a.Substring( 1 ); currentTab = button;
else if (wasOpen != paletteOpen)
return Rules.Info[ a.ToLowerInvariant() ].Traits.Get<BuildableInfo>().Description; paletteAnimating = true;
} };
}
void HandleBuildPalette( World world, string item, bool isLmb )
{ static string Description( string a )
var player = world.LocalPlayer; {
var unit = Rules.Info[item]; if( a[ 0 ] == '@' )
var queue = player.PlayerActor.traits.Get<Traits.ProductionQueue>(); return "any " + a.Substring( 1 );
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>(); else
var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item ); return Rules.Info[ a.ToLowerInvariant() ].Traits.Get<BuildableInfo>().Description;
}
if (isLmb)
{ static void HandleBuildPalette( World world, string item, bool isLmb )
if (producing != null && producing == queue.CurrentItem(unit.Category)) {
{ var player = world.LocalPlayer;
if (producing.Done) var unit = Rules.Info[item];
{ var queue = player.PlayerActor.traits.Get<Traits.ProductionQueue>();
if (unit.Traits.Contains<BuildingInfo>()) var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Game.controller.orderGenerator = new PlaceBuildingOrderGenerator(player.PlayerActor, item); var producing = queue.AllItems(unit.Category).FirstOrDefault( a => a.Item == item );
return;
} if (isLmb)
{
if (producing.Paused) if (producing != null && producing == queue.CurrentItem(unit.Category))
{ {
Game.IssueOrder(Order.PauseProduction(player, item, false)); if (producing.Done)
return; {
} if (unit.Traits.Contains<BuildingInfo>())
} Game.controller.orderGenerator = new PlaceBuildingOrderGenerator(player.PlayerActor, item);
return;
StartProduction(world, item); }
}
else if (producing.Paused)
{ {
if (producing != null) Game.IssueOrder(Order.PauseProduction(player, item, false));
{ return;
// instant cancel of things we havent really started yet, and things that are finished }
if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost) }
{
Sound.Play(eva.CancelledAudio); StartProduction(world, item);
Game.IssueOrder(Order.CancelProduction(player, item)); }
} else
else {
{ if (producing != null)
Sound.Play(eva.OnHoldAudio); {
Game.IssueOrder(Order.PauseProduction(player, item, true)); // instant cancel of things we havent really started yet, and things that are finished
} if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost)
} {
} Sound.Play(eva.CancelledAudio);
} Game.IssueOrder(Order.CancelProduction(player, item));
}
void StartProduction( World world, string item ) else
{ {
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>(); Sound.Play(eva.OnHoldAudio);
var unit = Rules.Info[item]; Game.IssueOrder(Order.PauseProduction(player, item, true));
}
Sound.Play(unit.Traits.Contains<BuildingInfo>() ? eva.BuildingSelectAudio : eva.UnitSelectAudio); }
Game.IssueOrder(Order.StartProduction(world.LocalPlayer, item, }
Game.controller.GetModifiers().HasModifier(Modifiers.Shift) ? 5 : 1)); }
static void StartProduction( World world, string item )
{
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
var unit = Rules.Info[item];
Sound.Play(unit.Traits.Contains<BuildingInfo>() ? eva.BuildingSelectAudio : eva.UnitSelectAudio);
Game.IssueOrder(Order.StartProduction(world.LocalPlayer, item,
Game.controller.GetModifiers().HasModifier(Modifiers.Shift) ? 5 : 1));
} }
static Dictionary<string, string> CategoryNameRemaps = new Dictionary<string, string> static Dictionary<string, string> CategoryNameRemaps = new Dictionary<string, string>
@@ -408,32 +417,32 @@ namespace OpenRA.Widgets
{ "Plane", "Aircraft" }, { "Plane", "Aircraft" },
{ "Ship", "Ships" }, { "Ship", "Ships" },
{ "Vehicle", "Vehicles" }, { "Vehicle", "Vehicles" },
}; };
void DrawBuildTabs( World world, int paletteHeight) void DrawBuildTabs( World world, int paletteHeight)
{ {
const int tabWidth = 24; const int tabWidth = 24;
const int tabHeight = 40; const int tabHeight = 40;
var x = paletteOrigin.X - tabWidth; var x = paletteOrigin.X - tabWidth;
var y = paletteOrigin.Y + 9; var y = paletteOrigin.Y + 9;
var queue = world.LocalPlayer.PlayerActor.traits.Get<Traits.ProductionQueue>(); var queue = world.LocalPlayer.PlayerActor.traits.Get<Traits.ProductionQueue>();
foreach (var q in tabImageNames) foreach (var q in tabImageNames)
{ {
var groupName = q.Key; var groupName = q.Key;
if (!visibleTabs.Contains(groupName)) if (!visibleTabs.Contains(groupName))
continue; continue;
string[] tabKeys = { "normal", "ready", "selected" }; string[] tabKeys = { "normal", "ready", "selected" };
var producing = queue.CurrentItem(groupName); var producing = queue.CurrentItem(groupName);
var index = q.Key == currentTab ? 2 : (producing != null && producing.Done) ? 1 : 0; var index = q.Key == currentTab ? 2 : (producing != null && producing.Done) ? 1 : 0;
var race = world.LocalPlayer.Country.Race; var race = world.LocalPlayer.Country.Race;
WidgetUtils.DrawRGBA(ChromeProvider.GetImage(Game.chrome.renderer,"tabs-"+tabKeys[index], race+"-"+q.Key), new float2(x, y)); WidgetUtils.DrawRGBA(ChromeProvider.GetImage(Game.chrome.renderer,"tabs-"+tabKeys[index], race+"-"+q.Key), new float2(x, y));
var rect = new Rectangle((int)x,(int)y,(int)tabWidth,(int)tabHeight); var rect = new Rectangle((int)x,(int)y,(int)tabWidth,(int)tabHeight);
buttons.Add(Pair.New(rect, HandleTabClick(groupName, world))); buttons.Add(Pair.New(rect, HandleTabClick(groupName, world)));
if (rect.Contains(Game.chrome.lastMousePos.ToPoint())) if (rect.Contains(Game.chrome.lastMousePos.ToPoint()))
{ {
var text = CategoryNameRemaps.ContainsKey(groupName) ? CategoryNameRemaps[groupName] : groupName; var text = CategoryNameRemaps.ContainsKey(groupName) ? CategoryNameRemaps[groupName] : groupName;
@@ -444,20 +453,20 @@ namespace OpenRA.Widgets
Game.chrome.renderer.BoldFont.DrawText(text, Game.chrome.renderer.BoldFont.DrawText(text,
new float2(rect.Left - sz.X - 20, rect.Top + 12), Color.White); new float2(rect.Left - sz.X - 20, rect.Top + 12), Color.White);
} }
y += tabHeight; y += tabHeight;
} }
Game.chrome.renderer.RgbaSpriteRenderer.Flush(); Game.chrome.renderer.RgbaSpriteRenderer.Flush();
} }
void DrawRightAligned(string text, int2 pos, Color c) void DrawRightAligned(string text, int2 pos, Color c)
{ {
Game.chrome.renderer.BoldFont.DrawText(text, Game.chrome.renderer.BoldFont.DrawText(text,
pos - new int2(Game.chrome.renderer.BoldFont.Measure(text).X, 0), c); pos - new int2(Game.chrome.renderer.BoldFont.Measure(text).X, 0), c);
} }
void DrawProductionTooltip(World world, string unit, int2 pos) void DrawProductionTooltip(World world, string unit, int2 pos)
{ {
pos.Y += 15; pos.Y += 15;
@@ -481,6 +490,9 @@ namespace OpenRA.Widgets
DrawRightAligned( "${0}".F(buildable.Cost), pos + new int2(-5,5), DrawRightAligned( "${0}".F(buildable.Cost), pos + new int2(-5,5),
world.LocalPlayer.Cash + world.LocalPlayer.Ore >= buildable.Cost ? Color.White : Color.Red); world.LocalPlayer.Cash + world.LocalPlayer.Ore >= buildable.Cost ? Color.White : Color.Red);
if (buildable.Hotkey != null)
DrawRightAligned("{0}".F(buildable.Hotkey.ToUpper()), pos + new int2(-5, 35),Color.White);
var bi = info.Traits.GetOrDefault<BuildingInfo>(); var bi = info.Traits.GetOrDefault<BuildingInfo>();
if (bi != null) if (bi != null)
DrawRightAligned("{1}{0}".F(bi.Power, bi.Power > 0 ? "+" : ""), pos + new int2(-5, 20), DrawRightAligned("{1}{0}".F(bi.Power, bi.Power > 0 ? "+" : ""), pos + new int2(-5, 20),
@@ -506,6 +518,43 @@ namespace OpenRA.Widgets
p.ToInt2(), Color.White); p.ToInt2(), Color.White);
Game.chrome.renderer.RgbaSpriteRenderer.Flush(); Game.chrome.renderer.RgbaSpriteRenderer.Flush();
} }
}
public static void DoBuildingHotkey(char c, World world)
{
if (Game.world.LocalPlayer == null) return;
var buildable = Rules.TechTree.BuildableItems(Game.world.LocalPlayer, Chrome.rootWidget.GetWidget<BuildPaletteWidget>("INGAME_BUILD_PALETTE").currentTab);
var toBuild = buildable.FirstOrDefault(b => Rules.Info[b.ToLowerInvariant()].Traits.Get<BuildableInfo>().Hotkey == c.ToString());
if (toBuild != null) Hotkey(world, toBuild);
}
public static void TabChange(bool shift)
{
var p = Chrome.rootWidget.GetWidget<BuildPaletteWidget>("INGAME_BUILD_PALETTE");
int size = p.visibleTabs.Count();
if (size > 0)
{
string last = p.visibleTabs.Last();
string first = p.visibleTabs.First();
int current = p.visibleTabs.IndexOf(p.currentTab);
if (!shift)
{
if (current + 1 >= size)
p.SetCurrentTab(p.visibleTabs.FirstOrDefault());
else
p.SetCurrentTab(p.visibleTabs[current + 1]);
}
else
{
if (current - 1 < 0)
p.SetCurrentTab(p.visibleTabs.LastOrDefault());
else
p.SetCurrentTab(p.visibleTabs[current - 1]);
}
}
}
}
} }

File diff suppressed because it is too large Load Diff