Everything is now OpenRA, not OpenRa

This commit is contained in:
alzeih
2010-02-27 21:10:22 +13:00
parent 11b926a422
commit 7881deca30
299 changed files with 26919 additions and 21 deletions

238
OpenRA.Game/Actor.cs Executable file
View File

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

77
OpenRA.Game/Chat.cs Normal file
View File

@@ -0,0 +1,77 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
class Chat
{
const int logLength = 10;
public List<Tuple<Color, string, string>> recentLines = new List<Tuple<Color, string, string>>();
public string typing = "";
public bool isChatting = true;
public void Toggle()
{
if( isChatting && typing.Length > 0 )
Game.IssueOrder( Order.Chat( typing ) );
typing = "";
if( Game.orderManager.GameStarted )
isChatting ^= true;
}
public void Reset()
{
typing = "";
isChatting = false;
}
public void TypeChar(char c)
{
if (c == '\b')
{
if (typing.Length > 0)
typing = typing.Remove(typing.Length - 1);
}
else
typing += c;
}
public void AddLine(Player p, string text)
{
AddLine(p.Color, p.PlayerName, text);
}
public void AddLine(Color c, string from, string text)
{
Log.Write( "Chat: {0}: {1}", from, text );
recentLines.Add(Tuple.New(c, from, text));
var eva = Game.world.LocalPlayer.PlayerActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.ChatBeep);
while (recentLines.Count > logLength) recentLines.RemoveAt(0);
}
}
}

1214
OpenRA.Game/Chrome.cs Normal file

File diff suppressed because it is too large Load Diff

114
OpenRA.Game/Combat.cs Normal file
View File

@@ -0,0 +1,114 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA
{
static class Combat /* some utility bits that are shared between various things */
{
public static void DoImpact(int2 loc, int2 visualLoc,
WeaponInfo weapon, ProjectileInfo projectile, WarheadInfo warhead, Actor firedBy)
{
var world = firedBy.World;
var targetTile = ((1f / Game.CellSize) * loc.ToFloat2()).ToInt2();
var isWater = world.IsWater(targetTile);
var hitWater = world.IsCellBuildable(targetTile, UnitMovementType.Float);
if (warhead.Explosion != 0)
world.AddFrameEndTask(
w => w.Add(new Explosion(w, visualLoc, warhead.Explosion, hitWater)));
var impactSound = warhead.ImpactSound;
if (hitWater && warhead.WaterImpactSound != null)
impactSound = warhead.WaterImpactSound;
if (impactSound != null) Sound.Play(impactSound + ".aud");
if (!isWater) world.Map.AddSmudge(targetTile, warhead);
if (warhead.Ore) world.Map.DestroyOre(targetTile.X, targetTile.Y);
var firepowerModifier = firedBy.traits
.WithInterface<IFirepowerModifier>()
.Select(a => a.GetFirepowerModifier())
.Product();
var maxSpread = GetMaximumSpread(weapon, warhead, firepowerModifier);
var hitActors = world.FindUnitsInCircle(loc, maxSpread);
foreach (var victim in hitActors)
victim.InflictDamage(firedBy,
(int)GetDamageToInflict(victim, loc, weapon, warhead, firepowerModifier), warhead);
}
static float GetMaximumSpread(WeaponInfo weapon, WarheadInfo warhead, float modifier)
{
return (int)(warhead.Spread * Math.Log(Math.Abs(weapon.Damage * modifier), 2));
}
static float GetDamageToInflict(Actor target, int2 loc, WeaponInfo weapon, WarheadInfo warhead, float modifier)
{
if (!WeaponValidForTarget(weapon, target))
return 0f;
var distance = (target.CenterLocation - loc).Length*1/24f;
var rawDamage = weapon.Damage * modifier * (float)Math.Exp(-distance / warhead.Spread);
var multiplier = warhead.EffectivenessAgainst(target.Info.Traits.Get<OwnedActorInfo>().Armor);
return rawDamage * multiplier;
}
public static bool WeaponValidForTarget(WeaponInfo weapon, Actor target)
{
var projectile = Rules.ProjectileInfo[weapon.Projectile];
var warhead = Rules.WarheadInfo[weapon.Warhead];
var unit = target.traits.GetOrDefault<Unit>();
if (warhead.EffectivenessAgainst(target.Info.Traits.Get<OwnedActorInfo>().Armor) <= 0)
return false;
if (target.traits.Contains<Submarine>())
return projectile.ASW;
if (unit != null && unit.Altitude > 0)
return projectile.AA;
if (projectile.UnderWater && !target.Info.Traits.Get<OwnedActorInfo>().WaterBound)
return false;
return projectile.AG;
}
public static bool HasAnyValidWeapons(Actor self, Actor target)
{
var info = self.Info.Traits.Get<AttackBaseInfo>();
if (info.PrimaryWeapon != null &&
WeaponValidForTarget(self.GetPrimaryWeapon(), target)) return true;
if (info.SecondaryWeapon != null &&
WeaponValidForTarget(self.GetSecondaryWeapon(), target)) return true;
return false;
}
}
}

146
OpenRA.Game/Controller.cs Normal file
View File

@@ -0,0 +1,146 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Orders;
using OpenRA.Traits;
namespace OpenRA
{
public class Controller : IHandleInput
{
public IOrderGenerator orderGenerator = new UnitOrderGenerator();
public Selection selection = new Selection();
public void CancelInputMode() { orderGenerator = new UnitOrderGenerator(); }
public bool ToggleInputMode<T>() where T : IOrderGenerator, new()
{
if (orderGenerator is T)
{
CancelInputMode();
return false;
}
else
{
orderGenerator = new T();
return true;
}
}
void ApplyOrders(World world, float2 xy, MouseInput mi)
{
if (orderGenerator == null) return;
var orders = orderGenerator.Order(world, xy.ToInt2(), mi).ToArray();
Game.orderManager.IssueOrders( orders );
var voicedActor = orders.Select(o => o.Subject)
.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.traits.Contains<Unit>());
var isMove = orders.Any(o => o.OrderString == "Move");
var isAttack = orders.Any( o => o.OrderString == "Attack" );
if (voicedActor != null)
{
if(voicedActor.traits.GetOrDefault<IMovement>().CanEnterCell(xy.ToInt2()))
Sound.PlayVoice(isAttack ? "Attack" : "Move", voicedActor);
if (isMove)
world.Add(new Effects.MoveFlash(world, Game.CellSize * xy));
}
}
float2 dragStart, dragEnd;
public bool HandleInput(World world, MouseInput mi)
{
var xy = Game.viewport.ViewToWorld(mi);
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
{
if (!(orderGenerator is PlaceBuildingOrderGenerator))
dragStart = dragEnd = xy;
ApplyOrders(world, xy, mi);
}
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Move)
dragEnd = xy;
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Up)
{
if (orderGenerator is UnitOrderGenerator)
{
var newSelection = world.SelectActorsInBox(Game.CellSize * dragStart, Game.CellSize * xy);
selection.Combine(world, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy);
}
dragStart = dragEnd = xy;
}
if (mi.Button == MouseButton.None && mi.Event == MouseInputEvent.Move)
dragStart = dragEnd = xy;
if (mi.Button == MouseButton.Right && mi.Event == MouseInputEvent.Down)
ApplyOrders(world, xy, mi);
return true;
}
public Pair<float2, float2>? SelectionBox
{
get
{
if (dragStart == dragEnd) return null;
return Pair.New(Game.CellSize * dragStart, Game.CellSize * dragEnd);
}
}
public float2 MousePosition { get { return dragEnd; } }
Modifiers modifiers;
public string ChooseCursor( World world )
{
int sync = world.SyncHash();
try
{
var mi = new MouseInput
{
Location = ( Game.CellSize * MousePosition - Game.viewport.Location ).ToInt2(),
Button = MouseButton.Right,
Modifiers = modifiers
};
return orderGenerator.GetCursor( world, MousePosition.ToInt2(), mi );
}
finally
{
if( sync != world.SyncHash() )
throw new InvalidOperationException( "Desync in Controller.ChooseCursor" );
}
}
public void SetModifiers(Modifiers mods) { modifiers = mods; }
}
}

36
OpenRA.Game/Cursor.cs Normal file
View File

@@ -0,0 +1,36 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using OpenRA.Graphics;
namespace OpenRA
{
public class Cursor
{
CursorSequence sequence;
public Cursor(string cursor)
{
sequence = SequenceProvider.GetCursorSequence(cursor);
}
public Sprite GetSprite(int frame) { return sequence.GetSprite(frame); }
public int2 GetHotspot() { return sequence.Hotspot; }
}
}

133
OpenRA.Game/Effects/Bullet.cs Executable file
View File

@@ -0,0 +1,133 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class Bullet : IEffect
{
readonly Player Owner;
readonly Actor FiredBy;
readonly WeaponInfo Weapon;
readonly ProjectileInfo Projectile;
readonly WarheadInfo Warhead;
readonly int2 Src;
readonly int2 Dest;
readonly int2 VisualDest;
readonly int SrcAltitude;
readonly int DestAltitude;
int t = 0;
Animation anim;
const int BaseBulletSpeed = 100; /* pixels / 40ms frame */
public Bullet(string weapon, Player owner, Actor firedBy,
int2 src, int2 dest, int srcAltitude, int destAltitude)
: this(Rules.WeaponInfo[weapon], owner, firedBy, src, dest, srcAltitude, destAltitude) { }
/* src, dest are *pixel* coords */
public Bullet(WeaponInfo weapon, Player owner, Actor firedBy,
int2 src, int2 dest, int srcAltitude, int destAltitude)
{
Owner = owner;
FiredBy = firedBy;
Src = src;
Dest = dest;
SrcAltitude = srcAltitude;
DestAltitude = destAltitude;
VisualDest = Dest + new int2(
firedBy.World.CosmeticRandom.Next(-10, 10),
firedBy.World.CosmeticRandom.Next(-10, 10));
Weapon = weapon;
Projectile = Rules.ProjectileInfo[Weapon.Projectile];
Warhead = Rules.WarheadInfo[Weapon.Warhead];
if (Projectile.Image != null && Projectile.Image != "none")
{
if (Projectile.Rotates)
anim = new Animation(Projectile.Image, () => Traits.Util.GetFacing((dest - src).ToFloat2(), 0));
else
anim = new Animation(Projectile.Image);
anim.PlayRepeating("idle");
}
}
int TotalTime() { return (Dest - Src).Length * BaseBulletSpeed / Weapon.Speed; }
public void Tick( World world )
{
t += 40;
if (t > TotalTime()) /* remove finished bullets */
{
world.AddFrameEndTask(w => w.Remove(this));
Combat.DoImpact(Dest, VisualDest - new int2( 0, DestAltitude ),
Weapon, Projectile, Warhead, FiredBy);
}
if (Projectile.Trail != null)
{
var at = (float)t / TotalTime();
var altitude = float2.Lerp(SrcAltitude, DestAltitude, at);
var pos = float2.Lerp(Src.ToFloat2(), VisualDest.ToFloat2(), at)
- 0.5f * anim.Image.size - new float2(0, altitude);
var highPos = (Projectile.High || Projectile.Arcing)
? (pos - new float2(0, (VisualDest - Src).Length * height * 4 * at * (1 - at)))
: pos;
world.AddFrameEndTask(w => w.Add(
new Smoke(w, highPos.ToInt2(), Projectile.Trail)));
}
}
const float height = .1f;
public IEnumerable<Renderable> Render()
{
if (anim != null)
{
var at = (float)t / TotalTime();
var altitude = float2.Lerp(SrcAltitude, DestAltitude, at);
var pos = float2.Lerp( Src.ToFloat2(), VisualDest.ToFloat2(), at)
- 0.5f * anim.Image.size - new float2( 0, altitude );
if (Projectile.High || Projectile.Arcing)
{
if (Projectile.Shadow)
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow");
var highPos = pos - new float2(0, (VisualDest - Src).Length * height * 4 * at * (1 - at));
yield return new Renderable(anim.Image, highPos - .5f * anim.Image.size, Owner.Palette);
}
else
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, Projectile.UnderWater ? "shadow" : Owner.Palette);
}
}
}
}

50
OpenRA.Game/Effects/Corpse.cs Executable file
View File

@@ -0,0 +1,50 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class Corpse : IEffect
{
readonly Animation anim;
readonly float2 pos;
readonly Player owner;
public Corpse(Actor fromActor, int death)
{
anim = new Animation(fromActor.traits.GetOrDefault<RenderSimple>().GetImage(fromActor));
anim.PlayThen("die{0}".F(death + 1),
() => fromActor.World.AddFrameEndTask(w => w.Remove(this)));
pos = fromActor.CenterLocation;
owner = fromActor.Owner;
}
public void Tick( World world ) { anim.Tick(); }
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette);
}
}
}

View File

@@ -0,0 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class DelayedAction : IEffect
{
Action a;
int delay;
public DelayedAction(int delay, Action a)
{
this.a = a;
this.delay = delay;
}
public void Tick( World world )
{
if (--delay <= 0)
world.AddFrameEndTask(w => { w.Remove(this); a(); });
}
public IEnumerable<Renderable> Render() { yield break; }
}
}

View File

@@ -0,0 +1,50 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public class Explosion : IEffect
{
Animation anim;
int2 pos;
public Explosion( World world, int2 pixelPos, int style, bool isWater)
{
this.pos = pixelPos;
var variantSuffix = isWater ? "w" : "";
anim = new Animation("explosion");
anim.PlayThen(style.ToString() + variantSuffix,
() => world.AddFrameEndTask(w => w.Remove(this)));
}
public void Tick( World world ) { anim.Tick(); }
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "effect");
}
public Player Owner { get { return null; } }
}
}

View File

@@ -0,0 +1,52 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class FlashTarget : IEffect
{
Actor target;
int remainingTicks = 4;
public FlashTarget(Actor target)
{
this.target = target;
foreach (var e in target.World.Effects.OfType<FlashTarget>().Where(a => a.target == target).ToArray())
target.World.Remove(e);
}
public void Tick( World world )
{
if (--remainingTicks == 0)
world.AddFrameEndTask(w => w.Remove(this));
}
public IEnumerable<Renderable> Render()
{
if (remainingTicks % 2 == 0)
foreach (var r in target.Render())
yield return r.WithPalette("highlight");
}
}
}

31
OpenRA.Game/Effects/IEffect.cs Executable file
View File

@@ -0,0 +1,31 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Effects
{
public interface IEffect
{
void Tick( World world );
IEnumerable<Renderable> Render();
}
}

View File

@@ -0,0 +1,64 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class LaserZap : IEffect
{
readonly int2 from, to;
readonly int radius;
int timeUntilRemove = 10; // # of frames
int totalTime = 10;
Color color;
public LaserZap(int2 from, int2 to, int radius, Color color)
{
this.from = from;
this.to = to;
this.color = color;
this.radius = radius;
}
public void Tick(World world)
{
if (timeUntilRemove <= 0)
world.AddFrameEndTask(w => w.Remove(this));
--timeUntilRemove;
}
public IEnumerable<Renderable> Render()
{
int alpha = (int)((1-(float)(totalTime-timeUntilRemove)/totalTime)*255);
Color rc = Color.FromArgb(alpha,color);
float2 unit = 1.0f/(from - to).Length*(from - to).ToFloat2();
float2 norm = new float2(-unit.Y, unit.X);
for (int i = -radius; i < radius; i++)
Game.world.WorldRenderer.lineRenderer.DrawLine(from + i * norm, to + i * norm, rc, rc);
yield break;
}
}
}

114
OpenRA.Game/Effects/Missile.cs Executable file
View File

@@ -0,0 +1,114 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class Missile : IEffect
{
readonly Actor FiredBy;
readonly WeaponInfo Weapon;
readonly ProjectileInfo Projectile;
readonly WarheadInfo Warhead;
float2 Pos;
readonly Actor Target;
readonly Animation anim;
int Facing;
int t;
int Altitude;
public Missile(WeaponInfo weapon, Player owner, Actor firedBy,
int2 src, Actor target, int altitude, int facing)
{
Weapon = weapon;
Projectile = Rules.ProjectileInfo[Weapon.Projectile];
Warhead = Rules.WarheadInfo[Weapon.Warhead];
FiredBy = firedBy;
Target = target;
Pos = src.ToFloat2();
Altitude = altitude;
Facing = facing;
if (Projectile.Image != null && Projectile.Image != "none")
{
if (Projectile.Rotates)
anim = new Animation(Projectile.Image, () => Facing);
else
anim = new Animation(Projectile.Image);
anim.PlayRepeating("idle");
}
}
const int MissileCloseEnough = 7;
const float Scale = .2f;
public void Tick( World world )
{
t += 40;
var targetUnit = Target.traits.GetOrDefault<Unit>();
var targetAltitude = targetUnit != null ? targetUnit.Altitude : 0;
Altitude += Math.Sign(targetAltitude - Altitude);
Traits.Util.TickFacing(ref Facing,
Traits.Util.GetFacing(Target.CenterLocation - Pos, Facing),
Projectile.ROT);
anim.Tick();
var dist = Target.CenterLocation - Pos;
if (dist.LengthSquared < MissileCloseEnough * MissileCloseEnough || Target.IsDead)
Explode(world);
var speed = Scale * Weapon.Speed * ((targetAltitude > 0 && Weapon.TurboBoost) ? 1.5f : 1f);
var angle = Facing / 128f * Math.PI;
var move = speed * -float2.FromAngle((float)angle);
Pos += move;
if (Projectile.Trail != null)
world.AddFrameEndTask(w => w.Add(
new Smoke(w, (Pos - 1.5f * move - new int2( 0, Altitude )).ToInt2(), Projectile.Trail)));
if (Projectile.RangeLimit != 0 && t > Projectile.RangeLimit * 40)
Explode(world);
}
void Explode(World world)
{
world.AddFrameEndTask(w => w.Remove(this));
if (t > Projectile.Arm * 40) /* don't blow up in our launcher's face! */
Combat.DoImpact(Pos.ToInt2(), Pos.ToInt2(), Weapon, Projectile, Warhead, FiredBy);
return;
}
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, Pos - 0.5f * anim.Image.size - new float2(0, Altitude), "effect");
}
}
}

View File

@@ -0,0 +1,47 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class MoveFlash : IEffect
{
Animation anim = new Animation("moveflsh");
float2 pos;
public MoveFlash( World world, float2 pos )
{
this.pos = pos;
anim.PlayThen( "idle",
() => world.AddFrameEndTask(
w => w.Remove( this ) ) );
}
public void Tick( World world ) { anim.Tick(); }
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "shadow");
}
}
}

View File

@@ -0,0 +1,47 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class RepairIndicator : IEffect
{
int framesLeft = (int)(Rules.General.RepairRate * 25 * 60 / 2);
Actor a;
Animation anim = new Animation("select");
public RepairIndicator(Actor a) { this.a = a; anim.PlayRepeating("repair"); }
public void Tick( World world )
{
if (--framesLeft == 0 || a.IsDead)
world.AddFrameEndTask(w => w.Remove(this));
}
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image,
a.CenterLocation - .5f * anim.Image.size, "chrome");
}
}
}

50
OpenRA.Game/Effects/Smoke.cs Executable file
View File

@@ -0,0 +1,50 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class Smoke : IEffect
{
readonly int2 pos;
readonly Animation anim;
public Smoke(World world, int2 pos, string trail)
{
this.pos = pos;
anim = new Animation(trail);
anim.PlayThen("idle",
() => world.AddFrameEndTask(w => w.Remove(this)));
}
public void Tick( World world )
{
anim.Tick();
}
public IEnumerable<Renderable> Render()
{
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, "effect");
}
}
}

104
OpenRA.Game/Effects/TeslaZap.cs Executable file
View File

@@ -0,0 +1,104 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Effects
{
class TeslaZap : IEffect
{
readonly int2 from, to;
readonly Sequence tesla;
int timeUntilRemove = 2; // # of frames
public TeslaZap( int2 from, int2 to )
{
this.from = from;
this.to = to;
this.tesla = SequenceProvider.GetSequence( "litning", "bright" );
}
public void Tick( World world )
{
if( timeUntilRemove <= 0 )
world.AddFrameEndTask( w => w.Remove( this ) );
--timeUntilRemove;
}
public IEnumerable<Renderable> Render()
{
if( from.X < to.X )
return DrawZap( from, to, tesla );
else if( from.X > to.X || from.Y > to.Y )
return DrawZap( to, from, tesla );
else
return DrawZap( from, to, tesla );
}
static IEnumerable<Renderable> DrawZap( int2 from, int2 to, Sequence tesla )
{
int2 d = to - from;
if( d.X < 8 )
{
var prev = new int2( 0, 0 );
var y = d.Y;
while( y >= prev.Y + 8 )
{
yield return new Renderable( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), "effect");
prev.Y += 8;
}
}
else
{
var prev = new int2( 0, 0 );
for( int i = 1 ; i < d.X ; i += 8 )
{
var y = i * d.Y / d.X;
if( y <= prev.Y - 8 )
{
yield return new Renderable(tesla.GetSprite(3), (float2)(from + prev - new int2(8, 16)), "effect");
prev.Y -= 8;
while( y <= prev.Y - 8 )
{
yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 16)), "effect");
prev.Y -= 8;
}
}
else if( y >= prev.Y + 8 )
{
yield return new Renderable(tesla.GetSprite(0), (float2)(from + prev - new int2(8, 8)), "effect");
prev.Y += 8;
while( y >= prev.Y + 8 )
{
yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 8)), "effect");
prev.Y += 8;
}
}
else
yield return new Renderable(tesla.GetSprite(1), (float2)(from + prev - new int2(8, 8)), "effect");
prev.X += 8;
}
}
}
}
}

90
OpenRA.Game/Exts.cs Normal file
View File

@@ -0,0 +1,90 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA
{
public static class Exts
{
public static bool HasModifier(this Modifiers k, Modifiers mod)
{
return (k & mod) == mod;
}
public static IEnumerable<T> SymmetricDifference<T>(this IEnumerable<T> xs, IEnumerable<T> ys)
{
// this is probably a shockingly-slow way to do this, but it's concise.
return xs.Except(ys).Concat(ys.Except(xs));
}
public static float Product(this IEnumerable<float> xs)
{
return xs.Aggregate(1f, (a, x) => a * x);
}
public static WeaponInfo GetPrimaryWeapon(this Actor self)
{
var info = self.Info.Traits.GetOrDefault<AttackBaseInfo>();
if (info == null) return null;
var weapon = info.PrimaryWeapon;
if (weapon == null) return null;
return Rules.WeaponInfo[weapon];
}
public static WeaponInfo GetSecondaryWeapon(this Actor self)
{
var info = self.Info.Traits.GetOrDefault<AttackBaseInfo>();
if (info == null) return null;
var weapon = info.SecondaryWeapon;
if (weapon == null) return null;
return Rules.WeaponInfo[weapon];
}
public static int GetMaxHP(this Actor self)
{
var oai = self.Info.Traits.GetOrDefault<OwnedActorInfo>();
if (oai == null) return 0;
return oai.HP;
}
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k )
where V : new()
{
return d.GetOrAdd( k, _ => new V() );
}
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k, Func<K, V> createFn )
{
V ret;
if( !d.TryGetValue( k, out ret ) )
d.Add( k, ret = createFn( k ) );
return ret;
}
}
}

427
OpenRA.Game/Game.cs Normal file
View File

@@ -0,0 +1,427 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Support;
using OpenRA.Traits;
using Timer = OpenRA.Support.Timer;
using System.Runtime.InteropServices;
using System.IO;
namespace OpenRA
{
public static class Game
{
public static readonly int CellSize = 24;
public static World world;
internal static Viewport viewport;
public static Controller controller;
internal static Chrome chrome;
public static UserSettings Settings;
internal static OrderManager orderManager;
public static bool skipMakeAnims = true;
internal static Renderer renderer;
static int2 clientSize;
static string mapName;
internal static Session LobbyInfo = new Session();
static bool changePending;
public static void LoadModPackages(Manifest manifest)
{
FileSystem.UnmountAll();
Timer.Time("reset: {0}");
foreach (var dir in manifest.Folders) FileSystem.Mount(dir);
foreach (var pkg in manifest.Packages) FileSystem.Mount(pkg);
Timer.Time("mount temporary packages: {0}");
}
public static void ChangeMap(string mapName)
{
Timer.Time( "----ChangeMap" );
var manifest = new Manifest(LobbyInfo.GlobalSettings.Mods);
Timer.Time( "manifest: {0}" );
Game.changePending = false;
Game.mapName = mapName;
SheetBuilder.Initialize(renderer);
LoadModPackages(manifest);
Rules.LoadRules(mapName, manifest);
Timer.Time( "load rules: {0}" );
world = null; // trying to access the old world will NRE, rather than silently doing it wrong.
Player.ResetPlayerColorList();
ChromeProvider.Initialize(manifest.Chrome);
world = new World();
Game.world.ActorAdded += a =>
{
if (a.Owner != null && a.Info.Traits.Contains<OwnedActorInfo>())
a.Owner.Shroud.Explore(a);
};
Timer.Time( "world: {0}" );
SequenceProvider.Initialize(manifest.Sequences);
viewport = new Viewport(clientSize, Game.world.Map.Offset, Game.world.Map.Offset + Game.world.Map.Size, renderer);
Timer.Time( "ChromeProv, SeqProv, viewport: {0}" );
skipMakeAnims = true;
foreach (var treeReference in Game.world.Map.Trees)
world.CreateActor(treeReference.Image, new int2(treeReference.Location), null);
Timer.Time( "trees: {0}" );
world.LoadMapActors(Rules.AllRules);
skipMakeAnims = false;
Timer.Time( "map actors: {0}" );
chrome = new Chrome(renderer);
Timer.Time( "chrome: {0}" );
Timer.Time( "----end ChangeMap" );
chat.AddLine(Color.White, "Debug", "Map change {0} -> {1}".F(Game.mapName, mapName));
}
internal static void Initialize(string mapName, Renderer renderer, int2 clientSize, int localPlayer, Controller controller)
{
Game.renderer = renderer;
Game.clientSize = clientSize;
// todo
Sound.Initialize();
PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false;
PerfHistory.items["text"].hasNormalTick = false;
Game.controller = controller;
ChangeMap(mapName);
if (Settings.Replay != "")
throw new NotImplementedException();
else
{
var connection = (string.IsNullOrEmpty(Settings.NetworkHost))
? new EchoConnection()
: new NetworkConnection( Settings.NetworkHost, Settings.NetworkPort );
orderManager = new OrderManager(connection, "replay.rep");
}
}
static int lastTime = Environment.TickCount;
public static void ResetTimer()
{
lastTime = Environment.TickCount;
}
public static int RenderFrame = 0;
internal static Chat chat = new Chat();
public static void Tick()
{
if (changePending && PackageDownloader.IsIdle())
{
ChangeMap(LobbyInfo.GlobalSettings.Map);
return;
}
int t = Environment.TickCount;
int dt = t - lastTime;
if (dt >= Settings.Timestep)
{
using (new PerfSample("tick_time"))
{
lastTime += Settings.Timestep;
chrome.Tick( world );
orderManager.TickImmediate( world );
if (orderManager.IsReadyForNextFrame)
{
orderManager.Tick(world);
controller.orderGenerator.Tick(world);
controller.selection.Tick(world);
world.Tick();
PerfHistory.Tick();
}
else
if (orderManager.FrameNumber == 0)
lastTime = Environment.TickCount;
}
}
using (new PerfSample("render"))
{
++RenderFrame;
viewport.DrawRegions( world );
}
PerfHistory.items["render"].Tick();
PerfHistory.items["batches"].Tick();
PerfHistory.items["text"].Tick();
}
public static void SyncLobbyInfo(string data)
{
var session = new Session();
session.GlobalSettings.Mods = Settings.InitialMods;
var ys = MiniYaml.FromString(data);
foreach (var y in ys)
{
if (y.Key == "GlobalSettings")
{
FieldLoader.Load(session.GlobalSettings, y.Value);
continue;
}
int index;
if (!int.TryParse(y.Key, out index))
continue; // not a player.
var client = new Session.Client();
FieldLoader.Load(client, y.Value);
session.Clients.Add(client);
world.players[index].SyncFromLobby(client);
}
LobbyInfo = session;
if (Game.orderManager.Connection.ConnectionState == ConnectionState.Connected)
world.SetLocalPlayer(Game.orderManager.Connection.LocalClientId);
if (Game.orderManager.FramesAhead != LobbyInfo.GlobalSettings.OrderLatency
&& !Game.orderManager.GameStarted)
{
Game.orderManager.FramesAhead = LobbyInfo.GlobalSettings.OrderLatency;
Game.chat.AddLine(Color.White, "Server",
"Order lag is now {0} frames.".F(LobbyInfo.GlobalSettings.OrderLatency));
}
if (PackageDownloader.SetPackageList(LobbyInfo.GlobalSettings.Packages)
|| mapName != LobbyInfo.GlobalSettings.Map)
changePending = true;
}
public static void IssueOrder(Order o) { orderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */
public static void StartGame()
{
Game.chat.Reset();
var taken = LobbyInfo.Clients.Where(c => c.SpawnPoint != 0)
.Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList();
var available = world.Map.SpawnPoints.Except(taken).ToList();
foreach (var client in LobbyInfo.Clients)
{
var sp = (client.SpawnPoint == 0)
? ChooseSpawnPoint(available, taken)
: world.Map.SpawnPoints.ElementAt(client.SpawnPoint - 1);
foreach (var ssu in world.players[client.Index].PlayerActor
.traits.WithInterface<IOnGameStart>())
ssu.SpawnStartingUnits(world.players[client.Index], sp);
}
Game.viewport.GoToStartLocation( Game.world.LocalPlayer );
orderManager.StartGame();
}
static int2 ChooseSpawnPoint(List<int2> available, List<int2> taken)
{
if (available.Count == 0)
throw new InvalidOperationException("No free spawnpoint.");
var n = taken.Count == 0
? world.SharedRandom.Next(available.Count)
: available // pick the most distant spawnpoint from everyone else
.Select((k,i) => Pair.New(k,i))
.OrderByDescending(a => taken.Sum(t => (t - a.First).LengthSquared))
.Select(a => a.Second)
.First();
var sp = available[n];
available.RemoveAt(n);
taken.Add(sp);
return sp;
}
static int2 lastPos;
public static void DispatchMouseInput(MouseInputEvent ev, MouseEventArgs e, Modifiers modifierKeys)
{
int sync = Game.world.SyncHash();
if (ev == MouseInputEvent.Down)
lastPos = new int2(e.Location);
if (ev == MouseInputEvent.Move && (e.Button == MouseButtons.Middle || e.Button == (MouseButtons.Left | MouseButtons.Right)))
{
var p = new int2(e.Location);
viewport.Scroll(lastPos - p);
lastPos = p;
}
Game.viewport.DispatchMouseInput( world,
new MouseInput
{
Button = (MouseButton)(int)e.Button,
Event = ev,
Location = new int2(e.Location),
Modifiers = modifierKeys,
});
if( sync != Game.world.SyncHash() )
throw new InvalidOperationException( "Desync in DispatchMouseInput" );
}
public static void HandleKeyDown( KeyEventArgs e )
{
//int sync = Game.world.SyncHash();
//if( sync != Game.world.SyncHash() )
// throw new InvalidOperationException( "Desync in OnKeyDown" );
}
public static bool IsHost
{
get { return orderManager.Connection.LocalClientId == 0; }
}
public static void HandleKeyPress( KeyPressEventArgs e, Modifiers modifiers )
{
int sync = Game.world.SyncHash();
if( e.KeyChar == '\r' )
Game.chat.Toggle();
else if( Game.chat.isChatting )
Game.chat.TypeChar( e.KeyChar );
else
if( e.KeyChar >= '0' && e.KeyChar <= '9' )
Game.controller.selection.DoControlGroup( world,
e.KeyChar - '0', modifiers );
if( sync != Game.world.SyncHash() )
throw new InvalidOperationException( "Desync in OnKeyPress" );
}
public static void HandleModifierKeys(Modifiers mods)
{
controller.SetModifiers(mods);
}
static Size GetResolution(Settings settings)
{
var desktopResolution = Screen.PrimaryScreen.Bounds.Size;
if (Game.Settings.Width > 0 && Game.Settings.Height > 0)
{
desktopResolution.Width = Game.Settings.Width;
desktopResolution.Height = Game.Settings.Height;
}
return new Size(
desktopResolution.Width,
desktopResolution.Height);
}
public static void PreInit(Settings settings)
{
while (!Directory.Exists("mods"))
{
var current = Directory.GetCurrentDirectory();
if (Directory.GetDirectoryRoot(current) == current)
throw new InvalidOperationException("Unable to load MIX files.");
Directory.SetCurrentDirectory("..");
}
LoadUserSettings(settings);
Game.LobbyInfo.GlobalSettings.Mods = Game.Settings.InitialMods;
// Load the default mod to access required files
Game.LoadModPackages(new Manifest(Game.LobbyInfo.GlobalSettings.Mods));
UiOverlay.ShowUnitDebug = Game.Settings.UnitDebug;
WorldRenderer.ShowUnitPaths = Game.Settings.PathDebug;
Renderer.SheetSize = Game.Settings.SheetSize;
bool windowed = !Game.Settings.Fullscreen;
var resolution = GetResolution(settings);
renderer = new Renderer(resolution, windowed);
resolution = renderer.Resolution;
var controller = new Controller(); /* a bit of insane input routing */
Game.Initialize(Game.Settings.Map, renderer, new int2(resolution), Game.Settings.Player, controller);
// ShowCursor(false);
Game.ResetTimer();
}
static void LoadUserSettings(Settings settings)
{
Game.Settings = new UserSettings();
var settingsFile = settings.GetValue("settings", "settings.ini");
FileSystem.Mount("./");
if (FileSystem.Exists(settingsFile))
FieldLoader.Load(Game.Settings,
new IniFile(FileSystem.Open(settingsFile)).GetSection("Settings"));
FileSystem.UnmountAll();
}
static bool quit;
internal static void Run()
{
while (!quit)
{
Game.Tick();
Application.DoEvents();
}
}
public static void Exit()
{
quit = true;
}
}
}

View File

@@ -0,0 +1,139 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class ActorInfo
{
public readonly string Name;
public readonly string Category;
public readonly TypeDictionary Traits = new TypeDictionary();
public ActorInfo( string name, MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
var mergedNode = MergeWithParent( node, allUnits ).Nodes;
Name = name;
MiniYaml categoryNode;
if( mergedNode.TryGetValue( "Category", out categoryNode ) )
Category = categoryNode.Value;
foreach( var t in mergedNode )
if( t.Key != "Inherits" && t.Key != "Category" )
Traits.Add( LoadTraitInfo( t.Key, t.Value ) );
}
static MiniYaml GetParent( MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
MiniYaml inherits;
node.Nodes.TryGetValue( "Inherits", out inherits );
if( inherits == null || string.IsNullOrEmpty( inherits.Value ) )
return null;
MiniYaml parent;
allUnits.TryGetValue( inherits.Value, out parent );
if( parent == null )
return null;
return parent;
}
static MiniYaml MergeWithParent( MiniYaml node, Dictionary<string, MiniYaml> allUnits )
{
var parent = GetParent( node, allUnits );
if( parent != null )
return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) );
return node;
}
static Pair<Assembly, string>[] ModAssemblies;
public static void LoadModAssemblies(Manifest m)
{
var asms = new List<Pair<Assembly, string>>();
// all the core stuff is in this assembly
asms.Add(Pair.New(typeof(ITraitInfo).Assembly, typeof(ITraitInfo).Namespace));
// add the mods
foreach (var a in m.Assemblies)
asms.Add(Pair.New(Assembly.LoadFile(Path.GetFullPath(a)), Path.GetFileNameWithoutExtension(a)));
ModAssemblies = asms.ToArray();
}
static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my)
{
if (traitName.Contains('@'))
traitName = traitName.Substring(0, traitName.IndexOf('@'));
foreach (var mod in ModAssemblies)
{
var fullTypeName = mod.Second + "." + traitName + "Info";
var info = (ITraitInfo)mod.First.CreateInstance(fullTypeName);
if (info == null) continue;
FieldLoader.Load(info, my);
return info;
}
throw new InvalidOperationException("Cannot locate trait: {0}".F(traitName));
}
public IEnumerable<ITraitInfo> TraitsInConstructOrder()
{
var ret = new List<ITraitInfo>();
var t = Traits.WithInterface<ITraitInfo>().ToList();
int index = 0;
while( t.Count != 0 )
{
if( index >= t.Count )
throw new InvalidOperationException( "Trait prerequisites not satisfied (or prerequisite loop)" );
var prereqs = PrerequisitesOf( t[ index ] );
if( prereqs.Count == 0 || prereqs.All( n => ret.Any( x => x.GetType().IsSubclassOf( n ) ) ) )
{
ret.Add( t[ index ] );
t.RemoveAt( index );
index = 0;
}
else
++index;
}
return ret;
}
static List<Type> PrerequisitesOf( ITraitInfo info )
{
return info
.GetType()
.GetInterfaces()
.Where( t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof( ITraitPrerequisite<> ) )
.Select( t => t.GetGenericArguments()[ 0 ] )
.ToList();
}
}
}

View File

@@ -0,0 +1,74 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
static class Footprint
{
public static IEnumerable<int2> Tiles( string name, BuildingInfo buildingInfo, int2 topLeft )
{
var dim = buildingInfo.Dimensions;
var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x));
if (buildingInfo.Bib)
{
dim.Y += 1;
footprint = footprint.Concat(new char[dim.X]);
}
return TilesWhere( name, dim, footprint.ToArray(), a => a != '_' ).Select( t => t + topLeft );
}
public static IEnumerable<int2> Tiles(Actor a, Traits.Building building)
{
return Tiles( a.Info.Name, a.Info.Traits.Get<BuildingInfo>(), a.Location );
}
public static IEnumerable<int2> UnpathableTiles( string name, BuildingInfo buildingInfo, int2 position )
{
var footprint = buildingInfo.Footprint.Where( x => !char.IsWhiteSpace( x ) ).ToArray();
foreach( var tile in TilesWhere( name, buildingInfo.Dimensions, footprint, a => a == 'x' ) )
yield return tile + position;
}
static IEnumerable<int2> TilesWhere( string name, int2 dim, char[] footprint, Func<char, bool> cond )
{
if( footprint.Length != dim.X * dim.Y )
throw new InvalidOperationException( "Invalid footprint for " + name );
int index = 0;
for( int y = 0 ; y < dim.Y ; y++ )
for( int x = 0 ; x < dim.X ; x++ )
if( cond( footprint[ index++ ] ) )
yield return new int2( x, y );
}
public static int2 AdjustForBuildingSize( BuildingInfo buildingInfo )
{
var dim = buildingInfo.Dimensions;
return new int2( dim.X / 2, dim.Y > 1 ? ( dim.Y + 1 ) / 2 : 0 );
}
}
}

View File

@@ -0,0 +1,112 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.GameRules
{
public class GeneralInfo
{
/* Special Weapons */
public readonly float GapRegenInterval =0;
public readonly int BadgerBombCount = 1;
/* Chrono Side Effects */
public readonly float QuakeChance = 0;
public readonly float QuakeDamage = 0; /* percent */
public readonly float VortexChance = 0;
public readonly int VortexDamage = 0;
public readonly int VortexRange = 0;
public readonly int VortexSpeed = 0;
/* Repair & Refit */
public readonly float RefundPercent = 0;
public readonly float ReloadRate = 0;
public readonly float RepairPercent = 0;
public readonly float RepairRate = 0;
public readonly int RepairStep = 0;
public readonly float URepairPercent = 0;
public readonly int URepairStep = 0;
/* Combat & Damage */
public readonly float TurboBoost = 1.5f;
public readonly float BallisticScatter = 0;
public readonly float C4Delay = 0;
public readonly float ExpSpread = 0;
public readonly int FireSupress = 0;
public readonly float HomingScatter = 0;
public readonly int MaxDamage = 0;
public readonly int MinDamage = 0;
public readonly bool OreExplosive = false;
public readonly bool PlayerAutoCrush = false;
public readonly bool PlayerReturnFire = false;
public readonly bool PlayerScatter = false;
public readonly bool TreeTargeting = false;
public readonly int Incoming = 0;
/* Income & Production */
public readonly float BuildSpeed = 0;
public readonly float BuildupTime = 0;
public readonly int GemValue = 0;
public readonly int GoldValue = 0;
public readonly float OreTruckRate = 0;
public readonly bool SeparateAircraft = true;
public readonly float SurvivorRate = 0;
/* Audo/Visual Map Controls */
public readonly bool AllyReveal = true;
public readonly float ConditionRed = 0;
public readonly float ConditionYellow = 0;
public readonly int DropZoneRadius = 0;
public readonly bool EnemyHealth = true;
public readonly int Gravity = 0;
public readonly float IdleActionFrequency = 0;
public readonly float MessageDelay = 0;
public readonly float MovieTime = 0;
public readonly bool NamedCivilians = false;
public readonly float SavourDelay = 0;
public readonly int ShroudRate = 0;
public readonly int SpeakDelay = 0;
public readonly int TimerWarning = 0;
public readonly bool FlashLowPower = false;
/* Computer & Movement Controls */
public readonly bool CurleyShuffle = false;
public readonly float BaseBias = 0;
public readonly float BaseDefenseDelay = 0;
public readonly float CloseEnough = 0;
public readonly int DamageDelay = 0;
public readonly int GameSpeeBias = 0;
public readonly int LZScanRadius = 0;
public readonly bool MineAware = false;
public readonly float Stray = 0;
public readonly float SubmergeDelay = 0;
public readonly float SuspendDelay = 0;
public readonly int SuspendPriority = 0;
public readonly float TeamDelay = 0;
/* Misc */
[Obsolete]
public readonly bool FineDiffControl = false;
/* OpenRA-specific */
public readonly int LowPowerSlowdown = 3; /* build time multiplier */
}
}

View File

@@ -0,0 +1,51 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using OpenRA.FileFormats;
namespace OpenRA.GameRules
{
public class InfoLoader<T> : IEnumerable<KeyValuePair<string, T>>
{
readonly Dictionary<string, T> infos = new Dictionary<string, T>();
public InfoLoader(params Pair<string, Func<string,T>>[] srcs)
{
foreach (var src in srcs)
foreach (var name in Rules.Categories[src.First])
{
var t = src.Second(name);
FieldLoader.Load(t, Rules.AllRules.GetSection(name));
infos[name] = t;
}
}
public T this[string name]
{
get { return infos[name.ToLowerInvariant()]; }
}
public IEnumerator<KeyValuePair<string, T>> GetEnumerator() { return infos.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return infos.GetEnumerator(); }
}
}

View File

@@ -0,0 +1,45 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.GameRules
{
public class ProjectileInfo
{
public readonly bool AA = false;
public readonly bool AG = true;
public readonly bool ASW = false;
public readonly bool Arcing = false;
public readonly int Arm = 0;
public readonly bool Degenerates = false;
public readonly bool High = false;
public readonly string Image = null;
public readonly bool Inaccurate = false;
public readonly bool Parachuted = false;
public readonly bool Proximity = false;
public readonly int ROT = 0;
public readonly bool Rotates = false;
public readonly bool Shadow = true;
public readonly bool UnderWater = false;
public readonly int RangeLimit = 0;
// OpenRA-specific:
public readonly string Trail = null;
}
}

82
OpenRA.Game/GameRules/Rules.cs Executable file
View File

@@ -0,0 +1,82 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
namespace OpenRA
{
public static class Rules
{
public static IniFile AllRules;
public static Dictionary<string, List<string>> Categories = new Dictionary<string, List<string>>();
public static InfoLoader<WeaponInfo> WeaponInfo;
public static InfoLoader<WarheadInfo> WarheadInfo;
public static InfoLoader<ProjectileInfo> ProjectileInfo;
public static InfoLoader<VoiceInfo> VoiceInfo;
public static GeneralInfo General;
public static TechTree TechTree;
public static Dictionary<string, ActorInfo> Info;
public static void LoadRules(string map, Manifest m)
{
var legacyRules = m.LegacyRules.Reverse().ToList();
legacyRules.Insert(0, map);
AllRules = new IniFile(legacyRules.Select(a => FileSystem.Open(a)).ToArray());
General = new GeneralInfo();
FieldLoader.Load(General, AllRules.GetSection("General"));
LoadCategories(
"Weapon",
"Warhead",
"Projectile",
"Voice");
WeaponInfo = new InfoLoader<WeaponInfo>(
Pair.New<string, Func<string, WeaponInfo>>("Weapon", _ => new WeaponInfo()));
WarheadInfo = new InfoLoader<WarheadInfo>(
Pair.New<string, Func<string, WarheadInfo>>("Warhead", _ => new WarheadInfo()));
ProjectileInfo = new InfoLoader<ProjectileInfo>(
Pair.New<string, Func<string, ProjectileInfo>>("Projectile", _ => new ProjectileInfo()));
VoiceInfo = new InfoLoader<VoiceInfo>(
Pair.New<string, Func<string, VoiceInfo>>("Voice", _ => new VoiceInfo()));
var yamlRules = m.Rules.Reverse().Select(a => MiniYaml.FromFile(a)).Aggregate(MiniYaml.Merge);
ActorInfo.LoadModAssemblies(m);
Info = new Dictionary<string, ActorInfo>();
foreach( var kv in yamlRules )
Info.Add(kv.Key.ToLowerInvariant(), new ActorInfo(kv.Key.ToLowerInvariant(), kv.Value, yamlRules));
TechTree = new TechTree();
}
static void LoadCategories(params string[] types)
{
foreach (var t in types)
Categories[t] = AllRules.GetSection(t + "Types").Select(x => x.Key.ToLowerInvariant()).ToList();
}
}
}

100
OpenRA.Game/GameRules/TechTree.cs Executable file
View File

@@ -0,0 +1,100 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class TechTree
{
readonly Cache<string, List<ActorInfo>> producesIndex = new Cache<string, List<ActorInfo>>(x => new List<ActorInfo>());
public TechTree()
{
foreach( var info in Rules.Info.Values )
{
var pi = info.Traits.GetOrDefault<ProductionInfo>();
if (pi != null)
foreach( var p in pi.Produces )
producesIndex[ p ].Add( info );
}
}
public Cache<string, List<Actor>> GatherBuildings( Player player )
{
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains<BuildingInfo>() ) )
{
ret[ b.Info.Name ].Add( b );
var buildable = b.Info.Traits.GetOrDefault<BuildableInfo>();
if( buildable != null )
foreach( var alt in buildable.AlternateName )
ret[ alt ].Add( b );
}
return ret;
}
public bool CanBuild( ActorInfo info, Player player, Cache<string, List<Actor>> playerBuildings )
{
var bi = info.Traits.GetOrDefault<BuildableInfo>();
if( bi == null ) return false;
if( !bi.Owner.Contains( player.Country.Race ) )
return false;
foreach( var p in bi.Prerequisites )
if( playerBuildings[ p ].Count == 0 )
return false;
if( producesIndex[ info.Category ].All( x => playerBuildings[ x.Name ].Count == 0 ) )
return false;
return true;
}
public IEnumerable<string> BuildableItems( Player player, params string[] categories )
{
var playerBuildings = GatherBuildings( player );
foreach( var unit in AllBuildables( player, categories ) )
if( CanBuild( unit, player, playerBuildings ) )
yield return unit.Name;
}
public IEnumerable<ActorInfo> AllBuildables(Player player, params string[] categories)
{
return Rules.Info.Values
.Where( x => x.Name[ 0 ] != '^' )
.Where( x => categories.Contains( x.Category ) )
.Where( x => x.Traits.Contains<BuildableInfo>() );
}
public IEnumerable<ActorInfo> UnitBuiltAt( ActorInfo info )
{
var builtAt = info.Traits.Get<BuildableInfo>().BuiltAt;
if( builtAt.Length != 0 )
return builtAt.Select( x => Rules.Info[ x.ToLowerInvariant() ] );
else
return producesIndex[ info.Category ];
}
}
}

View File

@@ -0,0 +1,53 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.GameRules
{
public class UserSettings
{
// Debug settings
public readonly bool UnitDebug = false;
public readonly bool PathDebug = false;
public readonly bool PerfGraph = true;
// Window settings
public readonly int Width = 0;
public readonly int Height = 0;
public readonly bool Fullscreen = false;
// Internal game settings
public readonly int Timestep = 40;
public readonly int SheetSize = 512;
// External game settings
public readonly string NetworkHost = "";
public readonly int NetworkPort = 0;
public readonly string Map = "scm12ea.ini";
public readonly int Player = 1;
public readonly string Replay = "";
public readonly string PlayerName = "";
public readonly string[] InitialMods = { "ra" };
// Gameplay options
// TODO: These need to die
public readonly bool RepairRequiresConyard = true;
public readonly bool PowerDownBuildings = true;
}
}

View File

@@ -0,0 +1,74 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.FileFormats;
namespace OpenRA.GameRules
{
public class VoiceInfo
{
public readonly string[] SovietVariants = { ".aud" };
public readonly string[] AlliedVariants = { ".aud" };
public readonly string[] Select = { };
public readonly string[] Move = { };
public readonly string[] Attack = null;
public readonly string[] Die = { };
public readonly Lazy<Dictionary<string, VoicePool>> Pools;
public VoiceInfo()
{
Pools = Lazy.New(() =>
new Dictionary<string, VoicePool>
{
{ "Select", new VoicePool(Select) },
{ "Move", new VoicePool(Move) },
{ "Attack", new VoicePool( Attack ?? Move ) },
{ "Die", new VoicePool(Die) },
});
}
}
public class VoicePool
{
readonly string[] clips;
readonly List<string> liveclips = new List<string>();
public VoicePool(params string[] clips)
{
this.clips = clips;
}
public string GetNext()
{
if (liveclips.Count == 0)
liveclips.AddRange(clips);
if (liveclips.Count == 0)
return null; /* avoid crashing if there's no clips at all */
var i = Game.world.CosmeticRandom.Next(liveclips.Count);
var s = liveclips[i];
liveclips.RemoveAt(i);
return s;
}
}
}

View File

@@ -0,0 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.GameRules
{
public class WarheadInfo
{
public readonly int Spread = 1;
public readonly float[] Verses = { 1, 1, 1, 1, 1 };
public readonly bool Wall = false;
public readonly bool Wood = false;
public readonly bool Ore = false;
public readonly int Explosion = 0;
public readonly int InfDeath = 0;
public readonly string ImpactSound = null;
public readonly string WaterImpactSound = null;
public float EffectivenessAgainst(ArmorType at) { return Verses[ (int)at ]; }
}
public enum ArmorType
{
none = 0,
wood = 1,
light = 2,
heavy = 3,
concrete = 4,
}
}

View File

@@ -0,0 +1,41 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.GameRules
{
public class WeaponInfo
{
public readonly int Burst = 1;
public readonly bool Charges = false;
public readonly int Damage = 0;
public readonly string Projectile = "Invisible";
public readonly int ROF = 1; // in 1/15 second units.
public readonly float Range = 0;
public readonly string Report = null;
public readonly int Speed = -1;
public readonly bool TurboBoost = false;
public readonly string Warhead = null;
public readonly bool RenderAsTesla = false;
public readonly bool RenderAsLaser = false;
public readonly bool UsePlayerColor = true;
public readonly int BeamRadius = 1;
}
}

View File

@@ -0,0 +1,150 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.Graphics
{
public class Animation
{
string name;
public Sequence CurrentSequence { get; private set; }
int frame = 0;
bool backwards = false;
bool tickAlways;
Func<int> facingFunc;
public string Name { get { return name; } }
public Animation( string name )
: this( name, () => 0 )
{
}
public Animation( string name, Func<int> facingFunc )
{
this.name = name.ToLowerInvariant();
this.tickFunc = () => { };
this.facingFunc = facingFunc;
}
public Sprite Image
{
get
{
return backwards
? CurrentSequence.GetSprite(CurrentSequence.End - frame - 1, facingFunc())
: CurrentSequence.GetSprite(frame, facingFunc());
}
}
public void Play( string sequenceName )
{
PlayThen(sequenceName, () => { });
}
public void PlayRepeating( string sequenceName )
{
PlayThen( sequenceName, () => PlayRepeating( CurrentSequence.Name ) );
}
public void ReplaceAnim(string sequenceName)
{
CurrentSequence = SequenceProvider.GetSequence(name, sequenceName);
frame %= CurrentSequence.Length;
}
public void PlayThen( string sequenceName, Action after )
{
after = after ?? ( () => { } );
backwards = false;
tickAlways = false;
CurrentSequence = SequenceProvider.GetSequence( name, sequenceName );
frame = 0;
tickFunc = () =>
{
++frame;
if( frame >= CurrentSequence.Length )
{
frame = CurrentSequence.Length - 1;
tickFunc = () => { };
after();
}
};
}
public void PlayBackwardsThen(string sequenceName, Action after)
{
PlayThen(sequenceName, after);
backwards = true;
}
public void PlayFetchIndex( string sequenceName, Func<int> func )
{
backwards = false;
tickAlways = true;
CurrentSequence = SequenceProvider.GetSequence( name, sequenceName );
frame = func();
tickFunc = () => frame = func();
}
int timeUntilNextFrame;
Action tickFunc;
public void Tick()
{
Tick( 40 ); // tick one frame
}
public bool HasSequence(string seq) { return SequenceProvider.HasSequence( name, seq ); }
public void Tick( int t )
{
if( tickAlways )
tickFunc();
else
{
timeUntilNextFrame -= t;
while( timeUntilNextFrame <= 0 )
{
tickFunc();
timeUntilNextFrame += 40; // 25 fps == 40 ms
}
}
}
public void ChangeImage(string newImage)
{
newImage = newImage.ToLowerInvariant();
if (name != newImage)
{
name = newImage.ToLowerInvariant();
ReplaceAnim(CurrentSequence.Name);
}
}
public Sequence GetSequence( string sequenceName )
{
return SequenceProvider.GetSequence( name, sequenceName );
}
}
}

View File

@@ -0,0 +1,97 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
static class ChromeProvider
{
static Dictionary<string, Dictionary<string, MappedImage>> collections;
static Dictionary<string, Sheet> cachedSheets;
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
public static void Initialize(params string[] chromeFiles)
{
collections = new Dictionary<string, Dictionary<string, MappedImage>>();
cachedSheets = new Dictionary<string, Sheet>();
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
foreach (var f in chromeFiles)
LoadChromeSource(f);
}
static void LoadChromeSource(string filename)
{
XmlDocument document = new XmlDocument();
document.Load(FileSystem.Open(filename));
foreach (XmlElement eCollection in document.SelectNodes("/chrome/collection"))
LoadChromeForCollection(eCollection);
}
static void LoadChromeForCollection(XmlElement eCollection)
{
string elementName = eCollection.GetAttribute("name");
string defaultSrc = (eCollection.HasAttribute("src") ? eCollection.GetAttribute("src") : null);
var images = eCollection.SelectNodes("./image").OfType<XmlElement>()
.Select(e => new MappedImage(defaultSrc, e))
.ToDictionary(s => s.Name);
collections.Add(elementName, images);
}
public static Sprite GetImage(Renderer renderer, string collection, string image)
{
// Cached sprite
if (cachedSprites.ContainsKey(collection) && cachedSprites[collection].ContainsKey(image))
return cachedSprites[collection][image];
MappedImage mi;
try { mi = collections[collection][image]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Collection `{0}` does not have an image `{1}`".F(collection, image));
}
// Cached sheet
Sheet sheet;
if (cachedSheets.ContainsKey(mi.Src))
sheet = cachedSheets[mi.Src];
else
{
sheet = new Sheet(renderer, mi.Src);
cachedSheets.Add(mi.Src, sheet);
}
// Cache the sprite
if (!cachedSprites.ContainsKey(collection))
cachedSprites.Add(collection, new Dictionary<string, Sprite>());
cachedSprites[collection].Add(image, mi.GetImage(renderer, sheet));
return cachedSprites[collection][image];
}
}
}

View File

@@ -0,0 +1,61 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Xml;
namespace OpenRA.Graphics
{
class CursorSequence
{
readonly int start, length;
public int Start { get { return start; } }
public int End { get { return start + length; } }
public int Length { get { return length; } }
public readonly int2 Hotspot;
Sprite[] sprites;
public CursorSequence(string cursorSrc, XmlElement e)
{
sprites = CursorSheetBuilder.LoadAllSprites(cursorSrc);
start = int.Parse(e.GetAttribute("start"));
if (e.GetAttribute("length") == "*" || e.GetAttribute("end") == "*")
length = sprites.Length - start;
else if (e.HasAttribute("length"))
length = int.Parse(e.GetAttribute("length"));
else if (e.HasAttribute("end"))
length = int.Parse(e.GetAttribute("end")) - start;
else
length = 1;
int.TryParse( e.GetAttribute("x"), out Hotspot.X );
int.TryParse( e.GetAttribute("y"), out Hotspot.Y );
}
public Sprite GetSprite(int frame)
{
return sprites[(frame % length) + start];
}
}
}

View File

@@ -0,0 +1,48 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
static class CursorSheetBuilder
{
static Cache<string, Sprite[]> cursors = new Cache<string, Sprite[]>(LoadCursors);
static readonly string[] exts = { ".shp" };
static Sprite[] LoadCursors(string filename)
{
try
{
var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.SharedInstance.Add(a.Image, a.Size)).ToArray();
}
catch (IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.SharedInstance.Add(a.Image, shp.Size)).ToArray();
}
}
public static Sprite[] LoadAllSprites(string filename) { return cursors[filename]; }
}
}

View File

@@ -0,0 +1,86 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
class HardwarePalette : Sheet
{
public const int MaxPalettes = 64;
int allocated = 0;
// We need to store the Palettes themselves for the remap palettes to work
// We should probably try to fix this somehow
static Dictionary<string, Palette> palettes;
static Dictionary<string, int> indices;
public HardwarePalette(Renderer renderer, Map map)
: base(renderer,new Size(256, MaxPalettes))
{
palettes = new Dictionary<string, Palette>();
indices = new Dictionary<string, int>();
}
public Palette GetPalette(string name)
{
try { return palettes[name]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Palette `{0}` does not exist".F(name));
}
}
public int GetPaletteIndex(string name)
{
try { return indices[name]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Palette `{0}` does not exist".F(name));
}
}
public int AddPalette(string name, Palette p)
{
palettes.Add(name, p);
indices.Add(name, allocated);
for (int i = 0; i < 256; i++)
{
this[new Point(i, allocated)] = p.GetColor(i);
}
return allocated++;
}
public void Update(IEnumerable<IPaletteModifier> paletteMods)
{
var b = new Bitmap(Bitmap);
foreach (var mod in paletteMods)
mod.AdjustPalette(b);
Texture.SetData(b);
Game.renderer.PaletteTexture = Texture;
}
}
}

View File

@@ -0,0 +1,89 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
class LineRenderer
{
Renderer renderer;
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */
const int linesPerBatch = 1024;
Vertex[] vertices = new Vertex[ 2 * linesPerBatch ];
ushort[] indices = new ushort[ 2 * linesPerBatch ];
int lines = 0;
int nv = 0, ni = 0;
public LineRenderer( Renderer renderer )
{
this.renderer = renderer;
vertexBuffer = renderer.Device.CreateVertexBuffer(vertices.Length );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
}
public void Flush()
{
if( lines > 0 )
{
renderer.LineShader.Render( () =>
{
vertexBuffer.SetData( vertices );
indexBuffer.SetData( indices );
renderer.DrawBatch( vertexBuffer, indexBuffer,
nv, ni / 2, null, PrimitiveType.LineList );
} );
nv = 0; ni = 0;
lines = 0;
}
}
public void DrawLine( float2 start, float2 end, Color startColor, Color endColor )
{
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( start,
new float2( startColor.R / 255.0f, startColor.G / 255.0f ),
new float2( startColor.B / 255.0f, startColor.A / 255.0f ) );
indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( end,
new float2( endColor.R / 255.0f, endColor.G / 255.0f ),
new float2( endColor.B / 255.0f, endColor.A / 255.0f ) );
if( ++lines >= linesPerBatch )
Flush();
}
public void FillRect( RectangleF r, Color color )
{
for (float y = r.Top; y < r.Bottom; y++)
{
DrawLine(new float2(r.Left, y), new float2(r.Right, y), color, color);
}
}
}
}

View File

@@ -0,0 +1,51 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
using System.IO;
using System.Xml;
namespace OpenRA.Graphics
{
class MappedImage
{
readonly Rectangle rect;
public readonly string Src;
public readonly string Name;
public MappedImage(string defaultSrc, XmlElement e)
{
Src = (e.HasAttribute("src")) ? e.GetAttribute("src") : defaultSrc;
Name = e.GetAttribute("name");
if (Src == null)
throw new InvalidDataException("Image src missing");
rect = new Rectangle(int.Parse(e.GetAttribute("x")),
int.Parse(e.GetAttribute("y")),
int.Parse(e.GetAttribute("width")),
int.Parse(e.GetAttribute("height")));
}
public Sprite GetImage(Renderer r, Sheet s)
{
return new Sprite(s, rect, TextureChannel.Alpha);
}
}
}

View File

@@ -0,0 +1,213 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
class Minimap
{
readonly World world;
Sheet sheet, mapOnlySheet;
SpriteRenderer rgbaRenderer;
LineRenderer lineRenderer;
Sprite sprite, mapOnlySprite;
Bitmap terrain, oreLayer;
Rectangle bounds;
Sprite ownedSpawnPoint;
Sprite unownedSpawnPoint;
const int alpha = 230;
public void Tick() { }
public Minimap(World world, Renderer r)
{
this.world = world;
sheet = new Sheet(r, new Size(128, 128));
mapOnlySheet = new Sheet(r, new Size(128, 128));
lineRenderer = new LineRenderer(r);
rgbaRenderer = new SpriteRenderer(r, true, r.RgbaSpriteShader);
var size = Math.Max(world.Map.Width, world.Map.Height);
var dw = (size - world.Map.Width) / 2;
var dh = (size - world.Map.Height) / 2;
bounds = new Rectangle(world.Map.Offset.X - dw, world.Map.Offset.Y - dh, size, size);
sprite = new Sprite(sheet, bounds, TextureChannel.Alpha);
mapOnlySprite = new Sprite(mapOnlySheet, bounds, TextureChannel.Alpha);
shroudColor = Color.FromArgb(alpha, Color.Black);
ownedSpawnPoint = ChromeProvider.GetImage(r, "spawnpoints", "owned");
unownedSpawnPoint = ChromeProvider.GetImage(r, "spawnpoints", "unowned");
}
public static Rectangle MakeMinimapBounds(Map m)
{
var size = Math.Max(m.Width, m.Height);
var dw = (size - m.Width) / 2;
var dh = (size - m.Height) / 2;
return new Rectangle(m.Offset.X - dw, m.Offset.Y - dh, size, size);
}
static Cache<string, Color[]> terrainTypeColors = new Cache<string, Color[]>(
theater =>
{
var pal = Game.world.WorldRenderer.GetPalette("terrain");
return new[] {
theater == "snow" ? 0xe3 :0x1a,
0x63, 0x2f, 0x1f, 0x14, 0x64, 0x1f, 0x68, 0x6b, 0x6d, 0x88 }
.Select(a => Color.FromArgb(alpha, pal.GetColor(a))).ToArray();
});
static Color shroudColor;
public void InvalidateOre() { oreLayer = null; }
public static Bitmap RenderTerrainBitmap(Map map, TileSet tileset)
{
var colors = terrainTypeColors[map.Theater.ToLowerInvariant()];
var terrain = new Bitmap(128, 128);
for (var y = 0; y < 128; y++)
for (var x = 0; x < 128; x++)
terrain.SetPixel(x, y, map.IsInMap(x, y)
? colors[tileset.GetWalkability(map.MapTiles[x, y])]
: shroudColor);
return terrain;
}
public static Bitmap RenderTerrainBitmapWithSpawnPoints(Map map, TileSet tileset)
{
/* todo: do this a bit nicer */
var terrain = RenderTerrainBitmap(map, tileset);
foreach (var sp in map.SpawnPoints)
terrain.SetPixel(sp.X, sp.Y, Color.White);
return terrain;
}
public void Update()
{
if (terrain == null)
terrain = RenderTerrainBitmap(world.Map, world.TileSet);
if (oreLayer == null)
{
var colors = terrainTypeColors[world.Map.Theater.ToLowerInvariant()];
oreLayer = new Bitmap(terrain);
for (var y = world.Map.YOffset; y < world.Map.YOffset + world.Map.Height; y++)
for (var x = world.Map.XOffset; x < world.Map.XOffset + world.Map.Width; x++)
if (world.Map.ContainsResource(new int2(x, y)))
oreLayer.SetPixel(x, y, colors[(int)TerrainMovementType.Ore]);
}
mapOnlySheet.Texture.SetData(oreLayer);
if (!world.Queries.OwnedBy[world.LocalPlayer].WithTrait<ProvidesRadar>().Any())
return;
var bitmap = new Bitmap(oreLayer);
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
var colors = terrainTypeColors[world.Map.Theater.ToLowerInvariant()];
int* c = (int*)bitmapData.Scan0;
foreach (var a in world.Queries.WithTrait<Unit>().Where( a => a.Actor.Owner != null ))
*(c + (a.Actor.Location.Y * bitmapData.Stride >> 2) + a.Actor.Location.X) =
Color.FromArgb(alpha, a.Actor.Owner.Color).ToArgb();
for (var y = world.Map.YOffset; y < world.Map.YOffset + world.Map.Height; y++)
for (var x = world.Map.XOffset; x < world.Map.XOffset + world.Map.Width; x++)
{
if (!world.LocalPlayer.Shroud.DisplayOnRadar(x, y))
{
*(c + (y * bitmapData.Stride >> 2) + x) = shroudColor.ToArgb();
continue;
}
var b = world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(new int2(x, y));
if (b != null)
*(c + (y * bitmapData.Stride >> 2) + x) =
(b.Owner != null ? Color.FromArgb(alpha, b.Owner.Color) : colors[4]).ToArgb();
}
}
bitmap.UnlockBits(bitmapData);
sheet.Texture.SetData(bitmap);
}
public void Draw(RectangleF rect, bool mapOnly)
{
rgbaRenderer.DrawSprite(mapOnly ? mapOnlySprite : sprite,
new float2(rect.X, rect.Y), "chrome", new float2(rect.Width, rect.Height));
rgbaRenderer.Flush();
}
int2 TransformCellToMinimapPixel(RectangleF viewRect, int2 p)
{
var fx = (float)(p.X - bounds.X) / bounds.Width;
var fy = (float)(p.Y - bounds.Y) / bounds.Height;
return new int2(
(int)(viewRect.Width * fx + viewRect.Left) - 8,
(int)(viewRect.Height * fy + viewRect.Top) - 8);
}
public void DrawSpawnPoints(RectangleF rect)
{
var points = world.Map.SpawnPoints
.Select( (sp,i) => Pair.New(sp,world.players.Values.FirstOrDefault(
p => p.SpawnPointIndex == i + 1 ) ))
.ToList();
foreach (var p in points)
{
var pos = TransformCellToMinimapPixel(rect, p.First);
if (p.Second == null)
rgbaRenderer.DrawSprite(unownedSpawnPoint, pos, "chrome");
else
{
lineRenderer.FillRect(new RectangleF(
Game.viewport.Location.X + pos.X + 2,
Game.viewport.Location.Y + pos.Y + 2,
12, 12), p.Second.Color);
rgbaRenderer.DrawSprite(ownedSpawnPoint, pos, "chrome");
}
}
lineRenderer.Flush();
rgbaRenderer.Flush();
}
}
}

View File

@@ -0,0 +1,114 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
class OverlayRenderer
{
static string[] overlaySpriteNames =
{
"sbag", "cycl", "brik", "fenc", "wood",
"gold01", "gold02", "gold03", "gold04",
"gem01", "gem02", "gem03", "gem04",
"v12", "v13", "v14", "v15", "v16", "v17", "v18",
"fpls", "wcrate", "scrate", "barb", "sbag",
};
static string[] smudgeSpriteNames =
{
"bib3", "bib2", "bib1", "sc1", "sc2", "sc3", "sc4", "sc5", "sc6",
"cr1", "cr2", "cr3", "cr4", "cr5", "cr6",
};
readonly Sprite[][] overlaySprites;
readonly Sprite[] smudgeSprites;
SpriteRenderer spriteRenderer;
Map map;
public OverlayRenderer( Renderer renderer, Map map )
{
this.spriteRenderer = new SpriteRenderer( renderer, true );
this.map = map;
overlaySprites = overlaySpriteNames.Select(f => SpriteSheetBuilder.LoadAllSprites(f)).ToArray();
smudgeSprites = smudgeSpriteNames.SelectMany(f => SpriteSheetBuilder.LoadAllSprites(f)).ToArray();
}
public void Draw()
{
var shroud = Game.world.LocalPlayer.Shroud;
for (int y = map.YOffset; y < map.YOffset + map.Height; y++)
for (int x = map.XOffset; x < map.XOffset + map.Width; x++)
{
if (!shroud.IsExplored(new int2(x,y))) continue;
var tr = map.MapTiles[x,y];
if (tr.smudge != 0 && tr.smudge <= smudgeSprites.Length)
{
var location = new int2(x, y);
spriteRenderer.DrawSprite(smudgeSprites[tr.smudge - 1],
Game.CellSize * (float2)location, "terrain");
}
var o = tr.overlay;
if (o < overlaySprites.Length)
{
var location = new int2(x, y);
var sprites = overlaySprites[o];
var spriteIndex = 0;
if (Ore.overlayIsFence[o]) spriteIndex = NearbyFences(x, y);
else if (Ore.overlayIsOre[o]) spriteIndex = map.MapTiles[x,y].density - 1;
else if (Ore.overlayIsGems[o]) spriteIndex = map.MapTiles[x,y].density - 1;
spriteRenderer.DrawSprite(sprites[spriteIndex],
Game.CellSize * (float2)location, "terrain");
}
}
spriteRenderer.Flush();
}
bool IsFence( int x, int y )
{
var o = map.MapTiles[ x, y ].overlay;
if (o < Ore.overlayIsFence.Length)
return Ore.overlayIsFence[o];
return false;
}
int NearbyFences( int x, int y )
{
int ret = 0;
if( IsFence( x, y - 1 ) )
ret |= 1;
if( IsFence( x + 1, y ) )
ret |= 2;
if( IsFence( x, y + 1 ) )
ret |= 4;
if( IsFence( x - 1, y ) )
ret |= 8;
return ret;
}
}
}

View File

@@ -0,0 +1,134 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Text;
using System.Reflection;
using System.Windows.Forms;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
using OpenRA.Support;
using System.IO;
namespace OpenRA.Graphics
{
internal class Renderer
{
internal static int SheetSize;
readonly IGraphicsDevice device;
public IShader SpriteShader { get; private set; } /* note: shared shader params */
public IShader LineShader { get; private set; }
public IShader RgbaSpriteShader { get; private set; }
public IShader WorldSpriteShader { get; private set; }
public ITexture PaletteTexture;
public readonly SpriteFont RegularFont, BoldFont;
public Size Resolution { get { return device.WindowSize; } }
public Renderer(Size resolution, bool windowed)
{
device = CreateDevice( Assembly.LoadFile( Path.GetFullPath( "OpenRA.Gl.dll" ) ), resolution.Width, resolution.Height, windowed, false );
SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx"));
LineShader = device.CreateShader(FileSystem.Open("shaders/line.fx"));
RgbaSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-rgba.fx"));
WorldSpriteShader = device.CreateShader(FileSystem.Open("shaders/chrome-shp.fx"));
// RegularFont = device.CreateFont( "FreeSans.ttf" );
// BoldFont = device.CreateFont( "FreeSansBold.ttf" );
RegularFont = new SpriteFont(this, "FreeSans.ttf", 14);
BoldFont = new SpriteFont(this, "FreeSansBold.ttf", 14);
}
IGraphicsDevice CreateDevice( Assembly rendererDll, int width, int height, bool windowed, bool vsync )
{
foreach( RendererAttribute r in rendererDll.GetCustomAttributes( typeof( RendererAttribute ), false ) )
{
return (IGraphicsDevice)r.Type.GetConstructor( new Type[] { typeof( int ), typeof( int ), typeof( bool ), typeof( bool ) } )
.Invoke( new object[] { width, height, windowed, vsync } );
}
throw new NotImplementedException();
}
public IGraphicsDevice Device { get { return device; } }
public void BeginFrame(float2 r1, float2 r2, float2 scroll)
{
device.Begin();
device.Clear(Color.Black);
SetShaderParams( SpriteShader, r1, r2, scroll );
SetShaderParams( LineShader, r1, r2, scroll );
SetShaderParams( RgbaSpriteShader, r1, r2, scroll );
SetShaderParams( WorldSpriteShader, r1, r2, scroll );
}
private void SetShaderParams( IShader s, float2 r1, float2 r2, float2 scroll )
{
s.SetValue( "Palette", PaletteTexture );
s.SetValue( "Scroll", scroll.X, scroll.Y );
s.SetValue( "r1", r1.X, r1.Y );
s.SetValue( "r2", r2.X, r2.Y );
s.Commit();
}
public void EndFrame()
{
device.End();
device.Present();
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
Range<int> vertexRange, Range<int> indexRange, ITexture texture, PrimitiveType type, IShader shader)
where T : struct
{
shader.SetValue("DiffuseTexture", texture);
shader.Commit();
vertices.Bind();
indices.Bind();
device.DrawIndexedPrimitives(type, vertexRange, indexRange);
PerfHistory.Increment("batches", 1);
}
public void DrawBatch<T>(IVertexBuffer<T> vertices, IIndexBuffer indices,
int vertexPool, int numPrimitives, ITexture texture, PrimitiveType type)
where T : struct
{
SpriteShader.SetValue("DiffuseTexture", texture);
SpriteShader.Commit();
vertices.Bind();
indices.Bind();
device.DrawIndexedPrimitives(type, vertexPool, numPrimitives);
PerfHistory.Increment("batches", 1);
}
}
}

View File

@@ -0,0 +1,70 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Xml;
namespace OpenRA.Graphics
{
public class Sequence
{
readonly Sprite[] sprites;
readonly int start, length, facings;
public readonly string Name;
public int Start { get { return start; } }
public int End { get { return start + length; } }
public int Length { get { return length; } }
public int Facings { get { return facings; } }
public Sequence(string unit, XmlElement e)
{
string srcOverride = e.GetAttribute("src");
Name = e.GetAttribute("name");
sprites = SpriteSheetBuilder.LoadAllSprites(string.IsNullOrEmpty(srcOverride) ? unit : srcOverride );
start = int.Parse(e.GetAttribute("start"));
if (e.GetAttribute("length") == "*" || e.GetAttribute("end") == "*")
length = sprites.Length - Start;
else if (e.HasAttribute("length"))
length = int.Parse(e.GetAttribute("length"));
else if (e.HasAttribute("end"))
length = int.Parse(e.GetAttribute("end")) - int.Parse(e.GetAttribute("start"));
else
length = 1;
if( e.HasAttribute( "facings" ) )
facings = int.Parse( e.GetAttribute( "facings" ) );
else
facings = 1;
}
public Sprite GetSprite( int frame )
{
return GetSprite( frame, 0 );
}
public Sprite GetSprite(int frame, int facing)
{
var f = Traits.Util.QuantizeFacing( facing, facings );
return sprites[ (f * length) + ( frame % length ) + start ];
}
}
}

View File

@@ -0,0 +1,101 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
static class SequenceProvider
{
static Dictionary<string, Dictionary<string, Sequence>> units;
static Dictionary<string, CursorSequence> cursors;
public static void Initialize(params string[] sequenceFiles)
{
units = new Dictionary<string, Dictionary<string, Sequence>>();
cursors = new Dictionary<string, CursorSequence>();
foreach (var f in sequenceFiles)
LoadSequenceSource(f);
}
static void LoadSequenceSource(string filename)
{
XmlDocument document = new XmlDocument();
document.Load(FileSystem.Open(filename));
foreach (XmlElement eUnit in document.SelectNodes("/sequences/unit"))
LoadSequencesForUnit(eUnit);
foreach (XmlElement eCursor in document.SelectNodes("/sequences/cursor"))
LoadSequencesForCursor(eCursor);
}
static void LoadSequencesForCursor(XmlElement eCursor)
{
string cursorSrc = eCursor.GetAttribute("src");
foreach (XmlElement eSequence in eCursor.SelectNodes("./sequence"))
cursors.Add(eSequence.GetAttribute("name"), new CursorSequence(cursorSrc, eSequence));
Log.Write("* LoadSequencesForCursor() done");
}
static void LoadSequencesForUnit(XmlElement eUnit)
{
string unitName = eUnit.GetAttribute("name");
Log.Write("Loading sequence {0}", unitName);
var sequences = eUnit.SelectNodes("./sequence").OfType<XmlElement>()
.Select(e => new Sequence(unitName, e))
.ToDictionary(s => s.Name);
units.Add(unitName, sequences);
}
public static Sequence GetSequence(string unitName, string sequenceName)
{
try { return units[unitName][sequenceName]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName));
}
}
public static bool HasSequence(string unit, string seq)
{
return units[unit].ContainsKey(seq);
}
public static CursorSequence GetCursorSequence(string cursor)
{
try { return cursors[cursor]; }
catch (KeyNotFoundException)
{
throw new InvalidOperationException(
"Cursor does not have a sequence `{0}`".F(cursor));
}
}
}
}

View File

@@ -0,0 +1,72 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
public class Sheet
{
readonly Renderer renderer;
protected readonly Bitmap bitmap;
ITexture texture;
internal Sheet(Renderer renderer, Size size)
{
this.renderer = renderer;
this.bitmap = new Bitmap(size.Width, size.Height);
}
internal Sheet(Renderer renderer, string filename)
{
this.renderer = renderer;
this.bitmap = (Bitmap)Image.FromStream(FileSystem.Open(filename));
}
void Resolve()
{
texture = renderer.Device.CreateTexture(bitmap);
}
public ITexture Texture
{
get
{
if (texture == null)
Resolve();
return texture;
}
}
public Size Size { get { return bitmap.Size; } }
protected Color this[Point p]
{
get { return bitmap.GetPixel(p.X, p.Y); }
set { bitmap.SetPixel(p.X, p.Y, value); }
}
public Bitmap Bitmap { get { return bitmap; } } // for perf
}
}

View File

@@ -0,0 +1,119 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
namespace OpenRA.Graphics
{
class SheetBuilder
{
public static SheetBuilder SharedInstance;
public static void Initialize(Renderer r)
{
SharedInstance = new SheetBuilder(r, TextureChannel.Red);
}
public SheetBuilder(Renderer r, TextureChannel ch)
{
renderer = r;
current = null;
rowHeight = 0;
channel = null;
initialChannel = ch;
}
public Sprite Add(byte[] src, Size size)
{
Sprite rect = Allocate(size);
Util.FastCopyIntoChannel(rect, src);
return rect;
}
public Sprite Add(Size size, byte paletteIndex)
{
byte[] data = new byte[size.Width * size.Height];
for (int i = 0; i < data.Length; i++)
data[i] = paletteIndex;
return Add(data, size);
}
Sheet NewSheet() { return new Sheet( renderer, new Size( Renderer.SheetSize, Renderer.SheetSize ) ); }
Renderer renderer;
Sheet current = null;
int rowHeight = 0;
Point p;
TextureChannel? channel = null;
TextureChannel initialChannel;
TextureChannel? NextChannel(TextureChannel? t)
{
if (t == null)
return initialChannel;
switch (t.Value)
{
case TextureChannel.Red: return TextureChannel.Green;
case TextureChannel.Green: return TextureChannel.Blue;
case TextureChannel.Blue: return TextureChannel.Alpha;
case TextureChannel.Alpha: return null;
default: return null;
}
}
public Sprite Allocate(Size imageSize)
{
if (current == null)
{
current = NewSheet();
channel = NextChannel(null);
}
if (imageSize.Width + p.X > current.Size.Width)
{
p = new Point(0, p.Y + rowHeight);
rowHeight = imageSize.Height;
}
if (imageSize.Height > rowHeight)
rowHeight = imageSize.Height;
if (p.Y + imageSize.Height > current.Size.Height)
{
if (null == (channel = NextChannel(channel)))
{
current = NewSheet();
channel = NextChannel(channel);
}
rowHeight = imageSize.Height;
p = new Point(0,0);
}
Sprite rect = new Sprite(current, new Rectangle(p, imageSize), channel.Value);
p.X += imageSize.Width;
return rect;
}
}
}

View File

@@ -0,0 +1,71 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
namespace OpenRA.Graphics
{
public class Sprite
{
public readonly Rectangle bounds;
public readonly Sheet sheet;
public readonly TextureChannel channel;
public readonly RectangleF uv;
public readonly float2 size;
readonly float2[] uvhax;
internal Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
{
this.bounds = bounds;
this.sheet = sheet;
this.channel = channel;
uv = new RectangleF(
(float)(bounds.Left) / sheet.Size.Width,
(float)(bounds.Top) / sheet.Size.Height,
(float)(bounds.Width) / sheet.Size.Width,
(float)(bounds.Height) / sheet.Size.Height);
uvhax = new float2[]
{
new float2( uv.Left, uv.Top ),
new float2( uv.Right, uv.Top ),
new float2( uv.Left, uv.Bottom ),
new float2( uv.Right, uv.Bottom ),
};
this.size = new float2(bounds.Size);
}
public float2 FastMapTextureCoords( int k )
{
return uvhax[ k ];
}
}
public enum TextureChannel
{
Red = 0,
Green = 1,
Blue = 2,
Alpha = 3,
}
}

View File

@@ -0,0 +1,116 @@
using System;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using Tao.FreeType;
using System.Runtime.InteropServices;
namespace OpenRA.Graphics
{
class SpriteFont
{
int size;
public SpriteFont(Renderer r, string name, int size)
{
this.size = size;
if (0 != FT.FT_New_Face(library, name, 0, out face))
throw new InvalidOperationException("FT_New_Face failed");
FT.FT_Set_Pixel_Sizes(face, 0, (uint)size);
glyphs = new Cache<char, GlyphInfo>(CreateGlyph);
// setup a 1-channel SheetBuilder for our private use
if (builder == null) builder = new SheetBuilder(r, TextureChannel.Alpha);
// precache glyphs for U+0020 - U+007f
for (var n = (char)0x20; n < (char)0x7f; n++)
if (glyphs[n] == null)
throw new InvalidOperationException();
}
public void DrawText(SpriteRenderer r, string text, float2 location, Color c)
{
location.Y += size; // baseline vs top
var p = location;
foreach (var s in text)
{
if (s == '\n')
{
location.Y += size;
p = location;
continue;
}
var g = glyphs[s];
r.DrawSprite(g.Sprite,
new float2(
(int)Math.Round(p.X + g.Offset.X, 0),
p.Y + g.Offset.Y),
"chrome");
p.X += g.Advance;
}
r.Flush();
}
public int2 Measure(string text)
{
return new int2((int)text.Split( '\n' ).Max( s => s.Sum(a => glyphs[a].Advance)), size);
}
Cache<char, GlyphInfo> glyphs;
IntPtr face;
GlyphInfo CreateGlyph(char c)
{
var index = FT.FT_Get_Char_Index(face, (uint)c);
FT.FT_Load_Glyph(face, index, FT.FT_LOAD_RENDER);
var _face = (FT_FaceRec)Marshal.PtrToStructure(face, typeof(FT_FaceRec));
var _glyph = (FT_GlyphSlotRec)Marshal.PtrToStructure(_face.glyph, typeof(FT_GlyphSlotRec));
var s = builder.Allocate(new Size(_glyph.metrics.width >> 6, _glyph.metrics.height >> 6));
var g = new GlyphInfo
{
Sprite = s,
Advance = _glyph.metrics.horiAdvance / 64f,
Offset = { X = _glyph.bitmap_left, Y = -_glyph.bitmap_top }
};
unsafe
{
var p = (byte*)_glyph.bitmap.buffer;
for (var j = 0; j < s.size.Y; j++)
{
for (var i = 0; i < s.size.X; i++)
if (p[i] != 0)
s.sheet.Bitmap.SetPixel(i + s.bounds.Left, j + s.bounds.Top,
Color.FromArgb(p[i], 0xff, 0xff, 0xff));
p += _glyph.bitmap.pitch;
}
}
return g;
}
static SpriteFont()
{
FT.FT_Init_FreeType(out library);
}
static IntPtr library;
static SheetBuilder builder;
}
class GlyphInfo
{
public float Advance;
public int2 Offset;
public Sprite Sprite;
}
}

View File

@@ -0,0 +1,91 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
class SpriteRenderer
{
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer;
Renderer renderer;
IShader shader;
const int spritesPerBatch = 1024;
Vertex[] vertices = new Vertex[4 * spritesPerBatch];
ushort[] indices = new ushort[6 * spritesPerBatch];
Sheet currentSheet = null;
int sprites = 0;
int nv = 0, ni = 0;
public SpriteRenderer(Renderer renderer, bool allowAlpha, IShader shader)
{
this.renderer = renderer;
this.shader = shader;
vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
}
public SpriteRenderer(Renderer renderer, bool allowAlpha)
: this(renderer, allowAlpha, renderer.SpriteShader) { }
public void Flush()
{
if (sprites > 0)
{
shader.SetValue( "DiffuseTexture", currentSheet.Texture );
shader.Render(() =>
{
vertexBuffer.SetData(vertices);
indexBuffer.SetData(indices);
renderer.DrawBatch(vertexBuffer, indexBuffer,
new Range<int>(0, nv),
new Range<int>(0, ni),
currentSheet.Texture, PrimitiveType.TriangleList,
shader);
});
nv = 0; ni = 0;
currentSheet = null;
sprites = 0;
}
}
public void DrawSprite(Sprite s, float2 location, string palette)
{
DrawSprite(s, location, palette, s.size);
}
public void DrawSprite(Sprite s, float2 location, string palette, float2 size)
{
if (s.sheet != currentSheet)
Flush();
currentSheet = s.sheet;
Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, Game.world.WorldRenderer.GetPaletteIndex(palette), nv, ni, size);
nv += 4; ni += 6;
if (++sprites >= spritesPerBatch)
Flush();
}
}
}

View File

@@ -0,0 +1,50 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
static class SpriteSheetBuilder
{
public static void Initialize( Map map )
{
exts = new[] {
"." + map.Theater.Substring( 0, 3 ).ToLowerInvariant(),
".shp",
".tem",
".sno",
".int" };
sprites = new Cache<string, Sprite[]>( LoadSprites );
}
static Cache<string, Sprite[]> sprites;
static string[] exts;
static Sprite[] LoadSprites(string filename)
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Select(a => SheetBuilder.SharedInstance.Add(a.Image, shp.Size)).ToArray();
}
public static Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
}
}

View File

@@ -0,0 +1,110 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
class TerrainRenderer
{
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer;
Sheet terrainSheet;
Renderer renderer;
Map map;
OverlayRenderer overlayRenderer;
public TerrainRenderer(World world, Renderer renderer, WorldRenderer wr)
{
this.renderer = renderer;
this.map = world.Map;
Size tileSize = new Size( Game.CellSize, Game.CellSize );
var tileMapping = new Cache<TileReference, Sprite>(
x => SheetBuilder.SharedInstance.Add(world.TileSet.GetBytes(x), tileSize));
Vertex[] vertices = new Vertex[4 * map.Height * map.Width];
ushort[] indices = new ushort[6 * map.Height * map.Width];
int nv = 0;
int ni = 0;
for( int j = map.YOffset ; j < map.YOffset + map.Height ; j++ )
for( int i = map.XOffset ; i < map.XOffset + map.Width; i++ )
{
Sprite tile = tileMapping[map.MapTiles[i, j]];
// TODO: The zero below should explicitly refer to the terrain palette, but this code is called
// before the palettes are created
Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, 0, nv, ni, tile.size);
nv += 4;
ni += 6;
}
terrainSheet = tileMapping[map.MapTiles[map.XOffset, map.YOffset]].sheet;
vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length );
vertexBuffer.SetData( vertices );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
indexBuffer.SetData( indices );
overlayRenderer = new OverlayRenderer( renderer, map );
}
public void Draw( Viewport viewport )
{
int indicesPerRow = map.Width * 6;
int verticesPerRow = map.Width * 4;
int visibleRows = (int)(viewport.Height / 24.0f + 2);
int firstRow = (int)((viewport.Location.Y) / 24.0f - map.YOffset);
int lastRow = firstRow + visibleRows;
if (lastRow < 0 || firstRow > map.Height)
return;
if (firstRow < 0) firstRow = 0;
if (lastRow > map.Height) lastRow = map.Height;
if (!Game.world.LocalPlayer.Shroud.HasGPS && Game.world.LocalPlayer.Shroud.bounds.HasValue)
{
var r = Game.world.LocalPlayer.Shroud.bounds.Value;
if (firstRow < r.Top - map.YOffset)
firstRow = r.Top - map.YOffset;
if (firstRow > r.Bottom - map.YOffset)
firstRow = r.Bottom - map.YOffset;
}
renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture );
renderer.SpriteShader.Render(() =>
renderer.DrawBatch(vertexBuffer, indexBuffer,
new Range<int>(verticesPerRow * firstRow, verticesPerRow * lastRow),
new Range<int>(indicesPerRow * firstRow, indicesPerRow * lastRow),
terrainSheet.Texture, PrimitiveType.TriangleList, renderer.SpriteShader));
overlayRenderer.Draw();
}
}
}

View File

@@ -0,0 +1,131 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics
{
static class Util
{
public static string[] ReadAllLines(Stream s)
{
List<string> result = new List<string>();
using (StreamReader reader = new StreamReader(s))
while(!reader.EndOfStream)
{
var line = reader.ReadLine();
if( !string.IsNullOrEmpty( line ) && line[0] != '#' )
result.Add( line );
}
return result.ToArray();
}
public static T[] MakeArray<T>(int count, Converter<int, T> f)
{
T[] result = new T[count];
for (int i = 0; i < count; i++)
result[i] = f(i);
return result;
}
static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni, float2 size)
{
var attrib = new float2(palette / (float)HardwarePalette.MaxPalettes, channelSelect[(int)r.channel]);
vertices[nv] = new Vertex(o,
r.FastMapTextureCoords(0), attrib);
vertices[nv + 1] = new Vertex(new float2(o.X + size.X, o.Y),
r.FastMapTextureCoords(1), attrib);
vertices[nv + 2] = new Vertex(new float2(o.X, o.Y + size.Y),
r.FastMapTextureCoords(2), attrib);
vertices[nv + 3] = new Vertex(new float2(o.X + size.X, o.Y + size.Y),
r.FastMapTextureCoords(3), attrib);
indices[ni] = (ushort)(nv);
indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1);
indices[ni + 2] = indices[ni + 5] = (ushort)(nv + 2);
indices[ni + 4] = (ushort)(nv + 3);
}
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
{
var bitmap = dest.sheet.Bitmap;
BitmapData bits = null;
uint[] channelMasks = { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };
int[] shifts = { 16, 8, 0, 24 };
uint mask = channelMasks[(int)dest.channel];
int shift = shifts[(int)dest.channel];
try
{
bits = bitmap.LockBits(dest.bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int width = dest.bounds.Width;
int height = dest.bounds.Height;
unsafe
{
fixed (byte* srcbase = &src[0])
{
byte* s = srcbase;
uint* t = (uint*)bits.Scan0.ToPointer();
int stride = bits.Stride >> 2;
for (int j = 0; j < height; j++)
{
uint* p = t;
for (int i = 0; i < width; i++, p++)
*p = (*p & ~mask) | ((mask & ((uint)*s++) << shift));
t += stride;
}
}
}
}
finally
{
bitmap.UnlockBits(bits);
}
}
public static Color Lerp(float t, Color a, Color b)
{
return Color.FromArgb(
LerpChannel(t, a.A, b.A),
LerpChannel(t, a.R, b.R),
LerpChannel(t, a.G, b.G),
LerpChannel(t, a.B, b.B));
}
public static int LerpChannel(float t, int a, int b)
{
return (int)((1 - t) * a + t * b);
}
}
}

View File

@@ -0,0 +1,151 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Network;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
interface IHandleInput
{
bool HandleInput(World world, MouseInput mi);
}
class Viewport
{
readonly float2 screenSize;
float2 scrollPosition;
readonly Renderer renderer;
public float2 Location { get { return scrollPosition; } }
public int Width { get { return (int)screenSize.X; } }
public int Height { get { return (int)screenSize.Y; } }
SpriteRenderer cursorRenderer;
int2 mousePos;
float cursorFrame = 0f;
public void Scroll(float2 delta)
{
scrollPosition = scrollPosition + delta;
}
public IEnumerable<IHandleInput> regions { get { return new IHandleInput[] { Game.chrome, Game.controller }; } }
public Viewport(float2 screenSize, int2 mapStart, int2 mapEnd, Renderer renderer)
{
this.screenSize = screenSize;
this.renderer = renderer;
cursorRenderer = new SpriteRenderer(renderer, true);
this.scrollPosition = Game.CellSize* mapStart;
}
public void DrawRegions( World world )
{
world.WorldRenderer.palette.Update(world.Queries.WithTraitMultiple<IPaletteModifier>().Select(t=>t.Trait));
float2 r1 = new float2(2, -2) / screenSize;
float2 r2 = new float2(-1, 1);
renderer.BeginFrame(r1, r2, scrollPosition);
if( Game.orderManager.GameStarted )
{
world.WorldRenderer.Draw();
Game.chrome.Draw( world );
if( Game.orderManager.Connection.ConnectionState == ConnectionState.NotConnected )
Game.chrome.DrawDialog("Connection lost.");
}
else
{
// what a hack. as soon as we have some real chrome stuff...
switch( Game.orderManager.Connection.ConnectionState )
{
case ConnectionState.Connecting:
Game.chrome.DrawDialog("Connecting to {0}:{1}...".F( Game.Settings.NetworkHost, Game.Settings.NetworkPort ));
break;
case ConnectionState.NotConnected:
Game.chrome.DrawDialog("Connection failed.");
break;
case ConnectionState.Connected:
Game.chrome.DrawLobby( world );
break;
}
}
var cursorName = Game.chrome.HitTest(mousePos) ? "default" : Game.controller.ChooseCursor( world );
var c = new Cursor(cursorName);
cursorRenderer.DrawSprite(c.GetSprite((int)cursorFrame), mousePos + Location - c.GetHotspot(), "cursor");
cursorRenderer.Flush();
renderer.EndFrame();
}
public void Tick()
{
cursorFrame += 0.5f;
}
IHandleInput dragRegion = null;
public void DispatchMouseInput(World world, MouseInput mi)
{
if (mi.Event == MouseInputEvent.Move)
mousePos = mi.Location;
if (dragRegion != null) {
dragRegion.HandleInput( world, mi );
if (mi.Event == MouseInputEvent.Up) dragRegion = null;
return;
}
dragRegion = regions.FirstOrDefault(r => r.HandleInput(world, mi));
if (mi.Event != MouseInputEvent.Down)
dragRegion = null;
}
public float2 ViewToWorld(MouseInput mi)
{
return (1 / 24.0f) * (new float2(mi.Location.X, mi.Location.Y) + Location);
}
public void Center(IEnumerable<Actor> actors)
{
if (!actors.Any()) return;
var avgPos = (1f / actors.Count()) * actors
.Select(a => a.CenterLocation)
.Aggregate((a, b) => a + b);
scrollPosition = (avgPos - .5f * new float2(Width, Height)).ToInt2();
}
public void GoToStartLocation( Player player )
{
Center( player.World.Queries.OwnedBy[ player ].WithTrait<Selectable>().Select( a => a.Actor ) );
}
}
}

View File

@@ -0,0 +1,315 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Graphics
{
public class WorldRenderer
{
readonly World world;
internal readonly TerrainRenderer terrainRenderer;
internal readonly SpriteRenderer spriteRenderer;
internal readonly LineRenderer lineRenderer;
internal readonly UiOverlay uiOverlay;
internal readonly Renderer renderer;
internal readonly HardwarePalette palette;
public static bool ShowUnitPaths = false;
internal WorldRenderer(World world, Renderer renderer)
{
this.world = world;
this.renderer = renderer;
terrainRenderer = new TerrainRenderer(world, renderer, this);
spriteRenderer = new SpriteRenderer(renderer, true);
lineRenderer = new LineRenderer(renderer);
uiOverlay = new UiOverlay(spriteRenderer);
palette = new HardwarePalette(renderer, world.Map);
Log.Write("Created worldrenderer");
}
public int GetPaletteIndex(string name)
{
return palette.GetPaletteIndex(name);
}
public Palette GetPalette(string name)
{
return palette.GetPalette(name);
}
public void AddPalette(string name, Palette pal)
{
palette.AddPalette(name, pal);
}
void DrawSpriteList(RectangleF rect,
IEnumerable<Renderable> images)
{
foreach (var image in images)
{
var loc = image.Pos;
if (loc.X > rect.Right || loc.X < rect.Left - image.Sprite.bounds.Width)
continue;
if (loc.Y > rect.Bottom || loc.Y < rect.Top - image.Sprite.bounds.Height)
continue;
spriteRenderer.DrawSprite(image.Sprite, loc, image.Palette);
}
}
class SpriteComparer : IComparer<Renderable>
{
public int Compare(Renderable x, Renderable y)
{
var result = x.ZOffset.CompareTo(y.ZOffset);
if (result == 0)
result = x.Pos.Y.CompareTo(y.Pos.Y);
return result;
}
}
Rectangle GetBoundsRect()
{
if (!world.LocalPlayer.Shroud.HasGPS && world.LocalPlayer.Shroud.bounds.HasValue)
{
var r = world.LocalPlayer.Shroud.bounds.Value;
var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X);
var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y);
var right = left + (int)(Game.CellSize * r.Width);
var bottom = top + (int)(Game.CellSize * r.Height);
if (left < 0) left = 0;
if (top < 0) top = 0;
if (right > Game.viewport.Width) right = Game.viewport.Width;
if (bottom > Game.viewport.Height) bottom = Game.viewport.Height;
return new Rectangle(left, top, right - left, bottom - top);
}
else
return new Rectangle(0, 0, Game.viewport.Width, Game.viewport.Height);
}
public void Draw()
{
var bounds = GetBoundsRect();
renderer.Device.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
terrainRenderer.Draw(Game.viewport);
var comparer = new SpriteComparer();
bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y);
var renderables = world.Actors.SelectMany(a => a.Render())
.OrderBy(r => r, comparer);
DrawSpriteList(bounds, renderables);
foreach (var e in world.Effects)
DrawSpriteList(bounds, e.Render());
uiOverlay.Draw( world );
spriteRenderer.Flush();
DrawBandBox();
if (Game.controller.orderGenerator != null)
Game.controller.orderGenerator.Render( world );
world.LocalPlayer.Shroud.Draw(spriteRenderer);
lineRenderer.Flush();
spriteRenderer.Flush();
}
void DrawBandBox()
{
var selbox = Game.controller.SelectionBox;
if (selbox == null) return;
var a = selbox.Value.First;
var b = new float2(selbox.Value.Second.X - a.X, 0);
var c = new float2(0, selbox.Value.Second.Y - a.Y);
lineRenderer.DrawLine(a, a + b, Color.White, Color.White);
lineRenderer.DrawLine(a + b, a + b + c, Color.White, Color.White);
lineRenderer.DrawLine(a + b + c, a + c, Color.White, Color.White);
lineRenderer.DrawLine(a, a + c, Color.White, Color.White);
foreach (var u in world.SelectActorsInBox(selbox.Value.First, selbox.Value.Second))
DrawSelectionBox(u, Color.Yellow, false);
}
public void DrawSelectionBox(Actor selectedUnit, Color c, bool drawHealthBar)
{
var bounds = selectedUnit.GetBounds(true);
var xy = new float2(bounds.Left, bounds.Top);
var Xy = new float2(bounds.Right, bounds.Top);
var xY = new float2(bounds.Left, bounds.Bottom);
var XY = new float2(bounds.Right, bounds.Bottom);
lineRenderer.DrawLine(xy, xy + new float2(4, 0), c, c);
lineRenderer.DrawLine(xy, xy + new float2(0, 4), c, c);
lineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), c, c);
lineRenderer.DrawLine(Xy, Xy + new float2(0, 4), c, c);
lineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c);
lineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c);
lineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c);
lineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c);
if (drawHealthBar)
{
DrawHealthBar(selectedUnit, xy, Xy);
DrawControlGroup(selectedUnit, xy);
// Only display pips and tags to the owner
if (selectedUnit.Owner == world.LocalPlayer)
{
DrawPips(selectedUnit, xY);
DrawTags(selectedUnit, new float2(.5f * (bounds.Left + bounds.Right ), xy.Y));
}
}
if (ShowUnitPaths)
{
var mobile = selectedUnit.traits.GetOrDefault<Mobile>();
if (mobile != null)
{
var path = mobile.GetCurrentPath();
var start = selectedUnit.Location;
foreach (var step in path)
{
lineRenderer.DrawLine(
Game.CellSize * start + new float2(12, 12),
Game.CellSize * step + new float2(12, 12),
Color.Red, Color.Red);
start = step;
}
}
}
}
void DrawHealthBar(Actor selectedUnit, float2 xy, float2 Xy)
{
var c = Color.Gray;
lineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c);
lineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c);
var healthAmount = (float)selectedUnit.Health / selectedUnit.Info.Traits.Get<OwnedActorInfo>().HP;
var healthColor = (healthAmount < Rules.General.ConditionRed) ? Color.Red
: (healthAmount < Rules.General.ConditionYellow) ? Color.Yellow
: Color.LimeGreen;
var healthColor2 = Color.FromArgb(
255,
healthColor.R / 2,
healthColor.G / 2,
healthColor.B / 2);
var z = float2.Lerp(xy, Xy, healthAmount);
lineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0, -4), c, c);
lineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c);
lineRenderer.DrawLine(xy + new float2(0, -3), z + new float2(0, -3), healthColor, healthColor);
lineRenderer.DrawLine(xy + new float2(0, -2), z + new float2(0, -2), healthColor2, healthColor2);
lineRenderer.DrawLine(xy + new float2(0, -4), z + new float2(0, -4), healthColor2, healthColor2);
}
// depends on the order of pips in TraitsInterfaces.cs!
static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray" };
static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
void DrawControlGroup(Actor selectedUnit, float2 basePosition)
{
var group = Game.controller.selection.GetControlGroupForActor(selectedUnit);
if (group == null) return;
var pipImages = new Animation("pips");
pipImages.PlayFetchIndex("groups", () => (int)group);
pipImages.Tick();
spriteRenderer.DrawSprite(pipImages.Image, basePosition + new float2(-8, 1), "chrome");
}
void DrawPips(Actor selectedUnit, float2 basePosition)
{
// If a mod wants to implement a unit with multiple pip sources, then they are placed on multiple rows
var pipxyBase = basePosition + new float2(-12, -7); // Correct for the offset in the shp file
var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows
foreach (var pips in selectedUnit.traits.WithInterface<IPips>())
{
foreach (var pip in pips.GetPips(selectedUnit))
{
var pipImages = new Animation("pips");
pipImages.PlayRepeating(pipStrings[(int)pip]);
spriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, "chrome");
pipxyOffset += new float2(4, 0);
if (pipxyOffset.X+5 > selectedUnit.GetBounds(false).Width)
{
pipxyOffset.X = 0;
pipxyOffset.Y -= 4;
}
}
// Increment row
pipxyOffset.X = 0;
pipxyOffset.Y -= 5;
}
}
void DrawTags(Actor selectedUnit, float2 basePosition)
{
// If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows
var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file
var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows
foreach (var tags in selectedUnit.traits.WithInterface<ITags>())
{
foreach (var tag in tags.GetTags())
{
if (tag == TagType.None)
continue;
var tagImages = new Animation("pips");
tagImages.PlayRepeating(tagStrings[(int)tag]);
spriteRenderer.DrawSprite(tagImages.Image, tagxyBase + tagxyOffset, "chrome");
// Increment row
tagxyOffset.Y += 8;
}
}
}
}
}

53
OpenRA.Game/MainWindow.cs Executable file
View File

@@ -0,0 +1,53 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Windows.Forms;
namespace OpenRA
{
[Flags]
public enum MouseButton
{
None = (int)MouseButtons.None,
Left = (int)MouseButtons.Left,
Right = (int)MouseButtons.Right,
Middle = (int)MouseButtons.Middle,
}
[Flags]
public enum Modifiers
{
None = (int)Keys.None,
Shift = (int)Keys.Shift,
Alt = (int)Keys.Alt,
Ctrl = (int)Keys.Control,
}
public struct MouseInput
{
public MouseInputEvent Event;
public int2 Location;
public MouseButton Button;
public Modifiers Modifiers;
}
public enum MouseInputEvent { Down, Move, Up };
}

142
OpenRA.Game/Network/Connection.cs Executable file
View File

@@ -0,0 +1,142 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using OpenRA.FileFormats;
namespace OpenRA.Network
{
enum ConnectionState
{
NotConnected,
Connecting,
Connected,
}
interface IConnection
{
int LocalClientId { get; }
ConnectionState ConnectionState { get; }
void Send( byte[] packet );
void Receive( Action<int, byte[]> packetFn );
}
class EchoConnection : IConnection
{
protected struct ReceivedPacket
{
public int FromClient;
public byte[] Data;
}
protected List<ReceivedPacket> receivedPackets = new List<ReceivedPacket>();
public virtual int LocalClientId
{
get { return 1; }
}
public virtual ConnectionState ConnectionState
{
get { return ConnectionState.Connected; }
}
public virtual void Send( byte[] packet )
{
if( packet.Length == 0 )
throw new NotImplementedException();
lock( this )
receivedPackets.Add( new ReceivedPacket { FromClient = LocalClientId, Data = packet } );
}
public virtual void Receive( Action<int, byte[]> packetFn )
{
List<ReceivedPacket> packets;
lock( this )
{
packets = receivedPackets;
receivedPackets = new List<ReceivedPacket>();
}
foreach( var p in packets )
packetFn( p.FromClient, p.Data );
}
}
class NetworkConnection : EchoConnection
{
TcpClient socket;
int clientId;
ConnectionState connectionState = ConnectionState.Connecting;
public NetworkConnection( string host, int port )
{
new Thread( _ =>
{
try
{
socket = new TcpClient( host, port );
var reader = new BinaryReader( socket.GetStream() );
var serverProtocol = reader.ReadInt32();
if (ProtocolVersion.Version != serverProtocol)
throw new InvalidOperationException(
"Protocol version mismatch. Server={0} Client={1}"
.F(serverProtocol, ProtocolVersion.Version));
clientId = reader.ReadInt32();
connectionState = ConnectionState.Connected;
for( ; ; )
{
var len = reader.ReadInt32();
var client = reader.ReadInt32();
var buf = reader.ReadBytes( len );
if( len == 0 )
throw new NotImplementedException();
lock( this )
receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } );
}
}
catch( SocketException )
{
connectionState = ConnectionState.NotConnected;
}
}
) { IsBackground = true }.Start();
}
public override int LocalClientId { get { return clientId; } }
public override ConnectionState ConnectionState { get { return connectionState; } }
public override void Send( byte[] packet )
{
base.Send( packet );
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( (int)packet.Length ) );
ms.Write( packet );
ms.WriteTo( socket.GetStream() );
}
}
}

182
OpenRA.Game/Network/Order.cs Executable file
View File

@@ -0,0 +1,182 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.IO;
using System.Linq;
namespace OpenRA
{
public sealed class Order
{
public readonly string OrderString;
public readonly Actor Subject;
public readonly Actor TargetActor;
public readonly int2 TargetLocation;
public readonly string TargetString;
public bool IsImmediate;
public Player Player { get { return Subject.Owner; } }
public Order(string orderString, Actor subject,
Actor targetActor, int2 targetLocation, string targetString)
{
this.OrderString = orderString;
this.Subject = subject;
this.TargetActor = targetActor;
this.TargetLocation = targetLocation;
this.TargetString = targetString;
}
public Order(string orderString, Actor subject)
: this(orderString, subject, null, int2.Zero, null) { }
public Order(string orderString, Actor subject, Actor targetActor)
: this(orderString, subject, targetActor, int2.Zero, null) { }
public Order(string orderString, Actor subject, int2 targetLocation)
: this(orderString, subject, null, targetLocation, null) { }
public Order(string orderString, Actor subject, string targetString)
: this(orderString, subject, null, int2.Zero, targetString) { }
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation)
: this(orderString, subject, targetActor, targetLocation, null) { }
public Order(string orderString, Actor subject, Actor targetActor, string targetString)
: this(orderString, subject, targetActor, int2.Zero, targetString) { }
public Order(string orderString, Actor subject, int2 targetLocation, string targetString)
: this(orderString, subject, null, targetLocation, targetString) { }
public byte[] Serialize()
{
if (IsImmediate) /* chat, whatever */
{
var ret = new MemoryStream();
var w = new BinaryWriter(ret);
w.Write((byte)0xfe);
w.Write(OrderString);
w.Write(TargetString);
return ret.ToArray();
}
switch (OrderString)
{
// Format:
// u8 : orderID.
// 0xFF: Full serialized order.
// varies: rest of order.
default:
// TODO: specific serializers for specific orders.
{
var ret = new MemoryStream();
var w = new BinaryWriter(ret);
w.Write( (byte)0xFF );
w.Write(OrderString);
w.Write(UIntFromActor(Subject));
w.Write(UIntFromActor(TargetActor));
w.Write(TargetLocation.X);
w.Write(TargetLocation.Y);
w.Write(TargetString != null);
if (TargetString != null)
w.Write(TargetString);
return ret.ToArray();
}
}
}
public static Order Deserialize(World world, BinaryReader r)
{
switch (r.ReadByte())
{
case 0xFF:
{
var order = r.ReadString();
var subjectId = r.ReadUInt32();
var targetActorId = r.ReadUInt32();
var targetLocation = new int2(r.ReadInt32(), 0);
targetLocation.Y = r.ReadInt32();
var targetString = null as string;
if (r.ReadBoolean())
targetString = r.ReadString();
Actor subject, targetActor;
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
return null;
return new Order( order, subject, targetActor, targetLocation, targetString);
}
case 0xfe:
{
var name = r.ReadString();
var data = r.ReadString();
return new Order( name, null, data ) { IsImmediate = true };
}
default:
throw new NotImplementedException();
}
}
static uint UIntFromActor(Actor a)
{
if (a == null) return 0xffffffff;
return a.ActorID;
}
static bool TryGetActorFromUInt(World world, uint aID, out Actor ret )
{
if( aID == 0xFFFFFFFF )
{
ret = null;
return true;
}
else
{
foreach( var a in world.Actors.Where( x => x.ActorID == aID ) )
{
ret = a;
return true;
}
ret = null;
return false;
}
}
// Named constructors for Orders.
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
public static Order Chat(string text)
{
return new Order("Chat", null, text) { IsImmediate = true };
}
public static Order StartProduction(Player subject, string item)
{
return new Order("StartProduction", subject.PlayerActor, item );
}
public static Order PauseProduction(Player subject, string item, bool pause)
{
return new Order("PauseProduction", subject.PlayerActor, new int2( pause ? 1 : 0, 0 ), item);
}
public static Order CancelProduction(Player subject, string item)
{
return new Order("CancelProduction", subject.PlayerActor, item);
}
}
}

78
OpenRA.Game/Network/OrderIO.cs Executable file
View File

@@ -0,0 +1,78 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace OpenRA.Network
{
static class OrderIO
{
public static void Write(this Stream s, byte[] buf)
{
s.Write(buf, 0, buf.Length);
}
public static void WriteFrameData(this Stream s, IEnumerable<Order> orders, int frameNumber)
{
var bytes = Serialize( orders, frameNumber );
s.Write( BitConverter.GetBytes( (int)bytes.Length ) );
s.Write( bytes );
}
public static byte[] Serialize( this IEnumerable<Order> orders, int frameNumber )
{
var ms = new MemoryStream();
ms.Write( BitConverter.GetBytes( frameNumber ) );
foreach( var o in orders.Select( o => o.Serialize() ) )
ms.Write( o );
return ms.ToArray();
}
public static List<Order> ToOrderList(this byte[] bytes, World world)
{
var ms = new MemoryStream(bytes, 4, bytes.Length - 4);
var reader = new BinaryReader(ms);
var ret = new List<Order>();
while( ms.Position < ms.Length )
{
var o = Order.Deserialize( world, reader );
if( o != null )
ret.Add( o );
}
return ret;
}
public static byte[] SerializeSync( this List<int> sync, int frameNumber )
{
var ms = new MemoryStream();
using( var writer = new BinaryWriter( ms ) )
{
writer.Write( frameNumber );
writer.Write( (byte)0x65 );
foreach( var s in sync )
writer.Write( s );
}
return ms.ToArray();
}
}
}

View File

@@ -0,0 +1,158 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.Network
{
class OrderManager
{
int frameNumber = 0;
public int FramesAhead = 0;
public bool GameStarted { get { return frameNumber != 0; } }
public IConnection Connection { get; private set; }
Dictionary<int, Dictionary<int, byte[]>> frameClientData =
new Dictionary<int, Dictionary<int, byte[]>>();
List<int> readyForFrames = new List<int>();
List<Order> localOrders = new List<Order>();
public void StartGame()
{
if (GameStarted) return;
frameNumber = 1;
for( int i = frameNumber ; i <= FramesAhead ; i++ )
Connection.Send( new List<Order>().Serialize( i ) );
}
public int FrameNumber { get { return frameNumber; } }
public OrderManager( IConnection conn )
{
Connection = conn;
}
public OrderManager( IConnection conn, string replayFilename )
: this( conn )
{
}
public void IssueOrders( Order[] orders )
{
foreach( var order in orders )
IssueOrder( order );
}
public void IssueOrder( Order order )
{
localOrders.Add( order );
}
public void TickImmediate( World world )
{
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
if( immediateOrders.Count != 0 )
Connection.Send( immediateOrders.Serialize( 0 ) );
localOrders.RemoveAll( o => o.IsImmediate );
var immediatePackets = new List<Pair<int, byte[]>>();
Connection.Receive(
( clientId, packet ) =>
{
var frame = BitConverter.ToInt32( packet, 0 );
if( packet.Length == 5 && packet[ 4 ] == 0xEF )
readyForFrames.Add( frame );
else if( packet.Length >= 5 && packet[ 4 ] == 0x65 )
CheckSync( packet );
else if( frame == 0 )
immediatePackets.Add( Pair.New( clientId, packet ) );
else
frameClientData.GetOrAdd( frame ).Add( clientId, packet );
} );
foreach( var p in immediatePackets )
foreach( var o in p.Second.ToOrderList( world ) )
UnitOrders.ProcessOrder( world, p.First, o );
}
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
void CheckSync( byte[] packet )
{
var frame = BitConverter.ToInt32( packet, 0 );
byte[] existingSync;
if( syncForFrame.TryGetValue( frame, out existingSync ) )
{
if( packet.Length != existingSync.Length )
OutOfSync( frame );
else
for( int i = 0 ; i < packet.Length ; i++ )
if( packet[ i ] != existingSync[ i ] )
OutOfSync( frame );
}
else
syncForFrame.Add( frame, packet );
}
void OutOfSync( int frame )
{
throw new InvalidOperationException( "out of sync in frame {0}".F( frame ) );
}
public bool IsReadyForNextFrame
{
get { return readyForFrames.Contains( FrameNumber ); }
}
public void Tick( World world )
{
if( !IsReadyForNextFrame )
throw new InvalidOperationException();
readyForFrames.RemoveAll( f => f <= FrameNumber );
Connection.Send( localOrders.Serialize( FrameNumber + FramesAhead ) );
localOrders.Clear();
var frameData = frameClientData[ FrameNumber ];
var sync = new List<int>();
sync.Add( world.SyncHash() );
foreach( var order in frameData.OrderBy( p => p.Key ).SelectMany( o => o.Value.ToOrderList( world ).Select( a => new { Client = o.Key, Order = a } ) ) )
{
UnitOrders.ProcessOrder( world, order.Client, order.Order );
sync.Add( world.SyncHash() );
}
var ss = sync.SerializeSync( FrameNumber );
Connection.Send( ss );
CheckSync( ss );
++frameNumber;
}
}
}

View File

@@ -0,0 +1,66 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Network
{
static class UnitOrders
{
public static void ProcessOrder( World world, int clientId, Order order )
{
switch( order.OrderString )
{
case "Chat":
{
var player = world.players.Values.Where( p => p.Index == clientId ).Single();
Game.chat.AddLine(player, order.TargetString);
break;
}
case "StartGame":
{
Game.chat.AddLine(Color.White, "Server", "The game has started.");
Game.StartGame();
break;
}
case "SyncInfo":
{
Game.SyncLobbyInfo(order.TargetString);
break;
}
case "FileChunk":
{
PackageDownloader.ReceiveChunk(order.TargetString);
break;
}
default:
{
if( !order.IsImmediate )
foreach (var t in order.Subject.traits.WithInterface<IResolveOrder>())
t.ResolveOrder(order.Subject, order);
break;
}
}
}
}
}

View File

@@ -0,0 +1,306 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OpenRA</RootNamespace>
<AssemblyName>OpenRA.Game</AssemblyName>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<ApplicationIcon>OpenRA.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;SANITY_CHECKS</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Tao.FreeType, Version=2.3.5.0, Culture=neutral, PublicKeyToken=e499629dc69cd531, processorArchitecture=MSIL" />
<Reference Include="Tao.OpenAl, Version=1.1.0.1, Culture=neutral, PublicKeyToken=a7579dda88828311, processorArchitecture=MSIL" />
</ItemGroup>
<ItemGroup>
<Compile Include="Chat.cs" />
<Compile Include="Chrome.cs" />
<Compile Include="Combat.cs" />
<Compile Include="Effects\Corpse.cs" />
<Compile Include="Effects\DelayedAction.cs" />
<Compile Include="Effects\FlashTarget.cs" />
<Compile Include="Effects\LaserZap.cs" />
<Compile Include="Effects\MoveFlash.cs" />
<Compile Include="Effects\RepairIndicator.cs" />
<Compile Include="Effects\Smoke.cs" />
<Compile Include="Effects\TeslaZap.cs" />
<Compile Include="Exts.cs" />
<Compile Include="GameRules\GeneralInfo.cs" />
<Compile Include="GameRules\ActorInfo.cs" />
<Compile Include="GameRules\TechTree.cs" />
<Compile Include="GameRules\UserSettings.cs" />
<Compile Include="GameRules\VoiceInfo.cs" />
<Compile Include="Effects\IEffect.cs" />
<Compile Include="Graphics\ChromeProvider.cs" />
<Compile Include="Graphics\MappedImage.cs" />
<Compile Include="Graphics\Minimap.cs" />
<Compile Include="Graphics\SpriteFont.cs" />
<Compile Include="Network\Connection.cs" />
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
<Compile Include="Effects\Missile.cs" />
<Compile Include="Network\OrderIO.cs" />
<Compile Include="Network\OrderManager.cs" />
<Compile Include="Orders\RepairOrderGenerator.cs" />
<Compile Include="Orders\SellOrderGenerator.cs" />
<Compile Include="Ore.cs" />
<Compile Include="PackageDownloader.cs" />
<Compile Include="PathSearch.cs" />
<Compile Include="Selection.cs" />
<Compile Include="Shroud.cs" />
<Compile Include="Smudge.cs" />
<Compile Include="Sound.cs" />
<Compile Include="Support\PerfHistory.cs" />
<Compile Include="Sync.cs" />
<Compile Include="Traits\Attack\AttackOmni.cs" />
<Compile Include="Traits\Chrome\PowerDownButton.cs" />
<Compile Include="Traits\CustomSellValue.cs" />
<Compile Include="Traits\Player\SpawnDefaultUnits.cs" />
<Compile Include="Traits\World\BridgeLoadHook.cs" />
<Compile Include="Traits\World\ChoosePaletteOnSelect.cs" />
<Compile Include="Traits\World\Country.cs" />
<Compile Include="Traits\World\CrateSpawner.cs" />
<Compile Include="Traits\World\OreGrowth.cs" />
<Compile Include="Traits\OreRefinery.cs" />
<Compile Include="Traits\Activities\Attack.cs" />
<Compile Include="Traits\Activities\CallFunc.cs" />
<Compile Include="Traits\Activities\EnterTransport.cs" />
<Compile Include="Traits\Activities\Fly.cs" />
<Compile Include="Traits\Activities\FlyAttack.cs" />
<Compile Include="Traits\Activities\FlyTimed.cs" />
<Compile Include="Traits\Activities\HeliAttack.cs" />
<Compile Include="Traits\Activities\HeliFly.cs" />
<Compile Include="Traits\Activities\HeliLand.cs" />
<Compile Include="Traits\Activities\HeliReturn.cs" />
<Compile Include="Traits\Activities\DeliverOre.cs" />
<Compile Include="Traits\Activities\TransformIntoActor.cs" />
<Compile Include="Actor.cs" />
<Compile Include="Effects\Bullet.cs" />
<Compile Include="Controller.cs" />
<Compile Include="Cursor.cs" />
<Compile Include="Effects\Explosion.cs" />
<Compile Include="GameRules\Footprint.cs" />
<Compile Include="GameRules\InfoLoader.cs" />
<Compile Include="GameRules\ProjectileInfo.cs" />
<Compile Include="GameRules\Rules.cs" />
<Compile Include="GameRules\WarheadInfo.cs" />
<Compile Include="GameRules\WeaponInfo.cs" />
<Compile Include="Graphics\Animation.cs" />
<Compile Include="Game.cs" />
<Compile Include="Graphics\CursorSequence.cs" />
<Compile Include="Graphics\CursorSheetBuilder.cs" />
<Compile Include="Graphics\LineRenderer.cs" />
<Compile Include="Graphics\OverlayRenderer.cs" />
<Compile Include="Graphics\WorldRenderer.cs" />
<Compile Include="Traits\Activities\Idle.cs" />
<Compile Include="Traits\Activities\Land.cs" />
<Compile Include="Traits\Activities\Rearm.cs" />
<Compile Include="Traits\Activities\RemoveSelf.cs" />
<Compile Include="Traits\Activities\Repair.cs" />
<Compile Include="Traits\Activities\ReturnToBase.cs" />
<Compile Include="Traits\Activities\Sell.cs" />
<Compile Include="Traits\Activities\Teleport.cs" />
<Compile Include="Orders\IOrderGenerator.cs" />
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
<Compile Include="Player.cs" />
<Compile Include="Graphics\Sheet.cs" />
<Compile Include="PathFinder.cs" />
<Compile Include="Graphics\Sequence.cs" />
<Compile Include="Network\Order.cs" />
<Compile Include="Graphics\SequenceProvider.cs" />
<Compile Include="Graphics\SheetBuilder.cs" />
<Compile Include="Graphics\HardwarePalette.cs" />
<Compile Include="MainWindow.cs">
</Compile>
<Compile Include="Support\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Graphics\Renderer.cs" />
<Compile Include="Support\Settings.cs" />
<Compile Include="Graphics\Sprite.cs" />
<Compile Include="Graphics\SpriteRenderer.cs" />
<Compile Include="Graphics\SpriteSheetBuilder.cs" />
<Compile Include="TerrainCosts.cs" />
<Compile Include="Graphics\TerrainRenderer.cs" />
<Compile Include="Traits\Activities\Harvest.cs" />
<Compile Include="Traits\Activities\Move.cs" />
<Compile Include="Traits\Activities\Follow.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\Activities\UndeployMcv.cs" />
<Compile Include="Traits\Activities\UnloadCargo.cs" />
<Compile Include="Traits\Attack\AttackBase.cs" />
<Compile Include="Traits\Attack\AttackFrontal.cs" />
<Compile Include="Traits\Attack\AttackHeli.cs" />
<Compile Include="Traits\Attack\AttackInfo.cs" />
<Compile Include="Traits\Attack\AttackPlane.cs" />
<Compile Include="Traits\Attack\AttackTurreted.cs" />
<Compile Include="Traits\AI\AutoHeal.cs" />
<Compile Include="Traits\AI\AutoTarget.cs" />
<Compile Include="Traits\Modifiers\BelowUnits.cs" />
<Compile Include="Traits\Bridge.cs" />
<Compile Include="Traits\Buildable.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\World\BuildingInfluence.cs" />
<Compile Include="Traits\CanPowerDown.cs" />
<Compile Include="Traits\Cargo.cs" />
<Compile Include="Traits\Chronoshiftable.cs" />
<Compile Include="Traits\World\ChronoshiftPaletteEffect.cs" />
<Compile Include="Traits\SupportPowers\ChronoshiftPower.cs" />
<Compile Include="Traits\Crate.cs" />
<Compile Include="Traits\Explodes.cs" />
<Compile Include="Traits\Fake.cs" />
<Compile Include="Traits\GeneratesGap.cs" />
<Compile Include="Traits\Harvester.cs" />
<Compile Include="Traits\Helicopter.cs" />
<Compile Include="Traits\Modifiers\InvisibleToOthers.cs" />
<Compile Include="Traits\ConstructionYard.cs" />
<Compile Include="Traits\World\LightPaletteRotator.cs" />
<Compile Include="Traits\LimitedAmmo.cs" />
<Compile Include="Traits\SupportPowers\NukePower.cs" />
<Compile Include="Traits\World\PaletteFromFile.cs" />
<Compile Include="Traits\World\PaletteFromRemap.cs" />
<Compile Include="Traits\World\PaletteFromRGBA.cs" />
<Compile Include="Traits\Passenger.cs" />
<Compile Include="Traits\Player\PlaceBuilding.cs" />
<Compile Include="Traits\World\PlayerColorPalette.cs" />
<Compile Include="Traits\World\ShroudPalette.cs" />
<Compile Include="Traits\SupportPowers\SupportPower.cs" />
<Compile Include="Traits\ProvidesRadar.cs" />
<Compile Include="Traits\Repairable.cs" />
<Compile Include="Traits\Reservable.cs" />
<Compile Include="Traits\Selectable.cs" />
<Compile Include="Traits\AI\SelfHealing.cs" />
<Compile Include="Traits\SquishByTank.cs" />
<Compile Include="Traits\Plane.cs" />
<Compile Include="Traits\Player\ProductionQueue.cs" />
<Compile Include="Traits\ProductionSurround.cs" />
<Compile Include="Traits\Render\RenderBuildingCharge.cs" />
<Compile Include="Traits\Render\RenderInfantry.cs" />
<Compile Include="Traits\TransformsOnDeploy.cs" />
<Compile Include="Traits\Mobile.cs" />
<Compile Include="Traits\Production.cs" />
<Compile Include="Traits\RallyPoint.cs" />
<Compile Include="Traits\Render\RenderBuilding.cs" />
<Compile Include="Traits\Render\RenderBuildingOre.cs" />
<Compile Include="Traits\Render\RenderBuildingTurreted.cs" />
<Compile Include="Traits\Render\RenderBuildingWarFactory.cs" />
<Compile Include="Traits\Render\RenderSimple.cs" />
<Compile Include="Traits\Modifiers\Cloak.cs" />
<Compile Include="Traits\Render\RenderUnit.cs" />
<Compile Include="Traits\Render\RenderUnitMuzzleFlash.cs" />
<Compile Include="Traits\Render\RenderUnitReload.cs" />
<Compile Include="Traits\Render\RenderUnitRotor.cs" />
<Compile Include="Traits\Render\RenderUnitSpinner.cs" />
<Compile Include="Traits\Render\RenderUnitTurreted.cs" />
<Compile Include="Traits\SeedsOre.cs" />
<Compile Include="Traits\StoresOre.cs" />
<Compile Include="Traits\Submarine.cs" />
<Compile Include="Traits\AI\TakeCover.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\Turreted.cs" />
<Compile Include="Traits\Unit.cs" />
<Compile Include="Traits\World\UnitInfluence.cs" />
<Compile Include="Traits\World\WaterPaletteRotation.cs" />
<Compile Include="Traits\Modifiers\WithShadow.cs" />
<Compile Include="Network\UnitOrders.cs" />
<Compile Include="Traits\Util.cs" />
<Compile Include="UiOverlay.cs" />
<Compile Include="Graphics\Util.cs" />
<Compile Include="Graphics\Viewport.cs" />
<Compile Include="Orders\UnitOrderGenerator.cs" />
<Compile Include="World.cs" />
<Compile Include="WorldUtils.cs" />
<Compile Include="Traits\Wall.cs" />
<Compile Include="Traits\Render\RenderBuildingWall.cs" />
<Compile Include="Traits\Player\EvaAlerts.cs" />
<Compile Include="Traits\World\ScreenShaker.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
<Project>{BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}</Project>
<Name>OpenRA.FileFormats</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
<Visible>False</Visible>
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
<Visible>False</Visible>
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Content Include="OpenRA.ico" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

BIN
OpenRA.Game/OpenRA.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

View File

@@ -0,0 +1,32 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
namespace OpenRA
{
public interface IOrderGenerator
{
IEnumerable<Order> Order( World world, int2 xy, MouseInput mi );
void Tick( World world );
void Render( World world );
string GetCursor( World world, int2 xy, MouseInput mi );
}
}

View File

@@ -0,0 +1,78 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class PlaceBuildingOrderGenerator : IOrderGenerator
{
readonly Actor Producer;
readonly string Building;
BuildingInfo BuildingInfo { get { return Rules.Info[ Building ].Traits.Get<BuildingInfo>(); } }
public PlaceBuildingOrderGenerator(Actor producer, string name)
{
Producer = producer;
Building = name;
}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
return InnerOrder(world, xy, mi);
}
IEnumerable<Order> InnerOrder(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
var topLeft = xy - Footprint.AdjustForBuildingSize( BuildingInfo );
if (!world.CanPlaceBuilding( Building, BuildingInfo, topLeft, null)
|| !world.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, topLeft))
{
var eva = world.LocalPlayer.PlayerActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.BuildingCannotPlaceAudio);
yield break;
}
yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, topLeft, Building);
}
}
public void Tick( World world )
{
var producing = Producer.traits.Get<Traits.ProductionQueue>().CurrentItem( Rules.Info[ Building ].Category );
if (producing == null || producing.Item != Building || producing.RemainingTime != 0)
Game.controller.CancelInputMode();
}
public void Render( World world )
{
world.WorldRenderer.uiOverlay.DrawBuildingGrid( world, Building, BuildingInfo );
}
public string GetCursor(World world, int2 xy, MouseInput mi) { return "default"; }
}
}

View File

@@ -0,0 +1,61 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class PowerDownOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
return OrderInner(world, xy, mi);
}
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.Owner == world.LocalPlayer
&& a.traits.Contains<CanPowerDown>())
.FirstOrDefault();
if (underCursor != null)
yield return new Order("PowerDown", underCursor);
}
}
public void Tick( World world ) { }
public void Render( World world ) { }
public string GetCursor(World world, int2 xy, MouseInput mi)
{
mi.Button = MouseButton.Left;
return OrderInner(world, xy, mi).Any()
? "powerdown" : "powerdown-blocked";
}
}
}

View File

@@ -0,0 +1,75 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class RepairOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
return OrderInner(world, xy, mi);
}
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.Owner == world.LocalPlayer
&& a.traits.Contains<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();
var building = underCursor != null ? underCursor.Info.Traits.Get<BuildingInfo>() : null;
if (building != null && building.Repairable && underCursor.Health < building.HP)
yield return new Order("Repair", underCursor);
}
}
public void Tick( World world )
{
if (!Game.Settings.RepairRequiresConyard)
return;
var hasFact = world.Queries.OwnedBy[world.LocalPlayer]
.WithTrait<ConstructionYard>()
.Any();
if (!hasFact)
Game.controller.CancelInputMode();
}
public void Render( World world ) {}
public string GetCursor(World world, int2 xy, MouseInput mi)
{
mi.Button = MouseButton.Left;
return OrderInner(world, xy, mi).Any()
? "repair" : "repair-blocked";
}
}
}

View File

@@ -0,0 +1,63 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class SellOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Right)
Game.controller.CancelInputMode();
return OrderInner(world, xy, mi);
}
IEnumerable<Order> OrderInner(World world, int2 xy, MouseInput mi)
{
if (mi.Button == MouseButton.Left)
{
var underCursor = world.FindUnitsAtMouse(mi.Location)
.Where(a => a.Owner == world.LocalPlayer
&& a.traits.Contains<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();
var building = underCursor != null ? underCursor.Info.Traits.Get<BuildingInfo>() : null;
if (building != null && !building.Unsellable)
yield return new Order("Sell", underCursor);
}
}
public void Tick( World world ) {}
public void Render( World world ) {}
public string GetCursor(World world, int2 xy, MouseInput mi)
{
mi.Button = MouseButton.Left;
return OrderInner(world, xy, mi).Any()
? "sell" : "sell-blocked";
}
}
}

View File

@@ -0,0 +1,102 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Orders
{
class UnitOrderGenerator : IOrderGenerator
{
public IEnumerable<Order> Order( World world, int2 xy, MouseInput mi )
{
foreach( var unit in Game.controller.selection.Actors )
{
var ret = unit.Order( xy, mi );
if( ret != null )
yield return ret;
}
}
public void Tick( World world ) {}
public void Render( World world )
{
foreach( var a in Game.controller.selection.Actors )
world.WorldRenderer.DrawSelectionBox( a, Color.White, true );
}
public string GetCursor( World world, int2 xy, MouseInput mi )
{
return ChooseCursor(world, mi);
}
string ChooseCursor( World world, MouseInput mi )
{
var p = Game.controller.MousePosition;
var c = Order(world, p.ToInt2(), mi)
.Select(o => CursorForOrderString(o.OrderString, o.Subject, o.TargetLocation))
.FirstOrDefault(a => a != null);
return c ??
(world.SelectActorsInBox(Game.CellSize * p,
Game.CellSize * p).Any()
? "select" : "default");
}
string CursorForOrderString(string s, Actor a, int2 location)
{
switch (s)
{
case "Attack": return "attack";
case "Heal": return "heal";
case "C4": return "c4";
case "Move":
if (a.traits.GetOrDefault<IMovement>().CanEnterCell(location))
return "move";
else
return "move-blocked";
case "DeployTransform":
var depInfo = a.Info.Traits.Get<TransformsOnDeployInfo>();
var transInfo = Rules.Info[depInfo.TransformsInto];
if (transInfo.Traits.Contains<BuildingInfo>())
{
var bi = transInfo.Traits.Get<BuildingInfo>();
if (!a.World.CanPlaceBuilding(depInfo.TransformsInto, bi, a.Location + new int2(depInfo.Offset[0], depInfo.Offset[1]), a))
return "deploy-blocked";
}
return "deploy";
case "Deploy": return "deploy";
case "Enter": return "enter";
case "EnterTransport": return "enter";
case "Deliver": return "enter";
case "Infiltrate": return "enter";
case "Capture": return "capture";
case "Harvest": return "attackmove";
case "Steal" : return "enter";
default:
return null;
}
}
}
}

207
OpenRA.Game/Ore.cs Normal file
View File

@@ -0,0 +1,207 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public static class Ore
{
public static void AddOre(this Map map, int i, int j)
{
if (map.ContainsOre(i, j) && map.MapTiles[i, j].density < 12)
map.MapTiles[i, j].density++;
else if (map.MapTiles[i, j].overlay == 0xff)
{
map.MapTiles[i, j].overlay = ChooseOre();
map.MapTiles[i, j].density = 1;
}
}
public static void DestroyOre(this Map map, int i, int j)
{
if (map.ContainsResource(new int2(i, j)))
{
map.MapTiles[i, j].density = 0;
map.MapTiles[i, j].overlay = 0xff;
}
}
public static bool OreCanSpreadInto(this World world, int i, int j)
{
if (world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(new int2(i, j)) != null)
return false;
return TerrainCosts.Cost(UnitMovementType.Wheel,
world.TileSet.GetWalkability(world.Map.MapTiles[i, j]))
< double.PositiveInfinity;
}
public static void SpreadOre(this World world, Random r, float chance)
{
var map = world.Map;
var mini = map.XOffset; var maxi = map.XOffset + map.Width;
var minj = map.YOffset; var maxj = map.YOffset + map.Height;
/* phase 1: grow into neighboring regions */
var newOverlay = new byte[128, 128];
for (int j = minj; j < maxj; j++)
for (int i = mini; i < maxi; i++)
{
newOverlay[i, j] = 0xff;
if (!map.HasOverlay(i, j)
&& r.NextDouble() < chance
&& map.GetOreDensity(i, j) > 0
&& world.OreCanSpreadInto(i, j))
newOverlay[i, j] = ChooseOre();
}
for (int j = minj; j < maxj; j++)
for (int i = mini; i < maxi; i++)
if (newOverlay[i, j] != 0xff)
map.MapTiles[i, j].overlay = newOverlay[i, j];
}
public static void GrowOre(this World world, Random r)
{
var map = world.Map;
var mini = map.XOffset; var maxi = map.XOffset + map.Width;
var minj = map.YOffset; var maxj = map.YOffset + map.Height;
/* phase 2: increase density of existing areas */
var newDensity = new byte[128, 128];
for (int j = minj; j < maxj; j++)
for (int i = mini; i < maxi; i++)
if (map.ContainsOre(i, j)) newDensity[i, j] = map.GetOreDensity(i, j);
for (int j = minj; j < maxj; j++)
for (int i = mini; i < maxi; i++)
if (map.MapTiles[i, j].density < newDensity[i, j])
++map.MapTiles[i, j].density;
}
public static void InitOreDensity( this Map map )
{
for (int j = 0; j < 128; j++)
for (int i = 0; i < 128; i++)
{
if (map.ContainsOre(i, j)) map.MapTiles[i, j].density = map.GetOreDensity(i, j);
if (map.ContainsGem(i, j)) map.MapTiles[i, j].density = map.GetGemDensity(i, j);
}
}
static byte GetOreDensity(this Map map, int i, int j)
{
int sum = 0;
for (var u = -1; u < 2; u++)
for (var v = -1; v < 2; v++)
if (map.ContainsOre(i + u, j + v))
++sum;
sum = (sum * 4 + 2) / 3;
return (byte)sum;
}
static byte GetGemDensity(this Map map, int i, int j)
{
int sum = 0;
for (var u = -1; u < 2; u++)
for (var v = -1; v < 2; v++)
if (map.ContainsGem(i + u, j + v))
++sum;
sum = (sum+2) / 3; /* 3 gem units/tile is full. */
return (byte)sum;
}
static bool HasOverlay(this Map map, int i, int j)
{
return map.MapTiles[i, j].overlay < overlayIsOre.Length;
}
static bool ContainsOre(this Map map, int i, int j)
{
return map.HasOverlay(i, j) && overlayIsOre[map.MapTiles[i, j].overlay];
}
static bool ContainsGem(this Map map, int i, int j)
{
return map.HasOverlay(i, j) && overlayIsGems[map.MapTiles[i, j].overlay];
}
public static bool ContainsResource(this Map map, int2 p)
{
return map.ContainsGem(p.X, p.Y) || map.ContainsOre(p.X, p.Y);
}
public static bool Harvest(this Map map, int2 p, out bool isGems) /* harvests one unit if possible */
{
isGems = map.ContainsGem(p.X, p.Y);
if (map.MapTiles[p.X, p.Y].density == 0) return false;
if (--map.MapTiles[p.X, p.Y].density == 0)
map.MapTiles[p.X, p.Y].overlay = 0xff;
return true;
}
static byte ore = 5;
static byte ChooseOre()
{
if (++ore > 8) ore = 5;
return ore;
}
public static bool IsOverlaySolid(this Map map, int2 p)
{
var o = map.MapTiles[p.X, p.Y].overlay;
return o < overlayIsFence.Length && overlayIsFence[o];
}
public static bool[] overlayIsFence =
{
true, true, true, true, true,
false, false, false, false,
false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, true, true,
};
public static bool[] overlayIsOre =
{
false, false, false, false, false,
true, true, true, true,
false, false, false, false,
false, false, false, false, false, false, false,
false, false, false, false, false,
};
public static bool[] overlayIsGems =
{
false, false, false, false, false,
false, false, false, false,
true, true, true, true,
false, false, false, false, false, false, false,
false, false, false, false, false,
};
}
}

View File

@@ -0,0 +1,144 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using OpenRA.FileFormats;
namespace OpenRA
{
static class PackageDownloader
{
static string[] allPackages = { };
static List<string> missingPackages = new List<string>();
static string currentPackage = null;
static MemoryStream content = null;
public static string CurrentPackage { get { return currentPackage; } }
public static int RemainingPackages { get { return missingPackages.Count; } }
public static float Fraction { get; private set; }
public static int DownloadedBytes { get { return (int)content.Length; } }
public static bool SetPackageList(string[] packages)
{
if (!(allPackages.Except(packages).Any()
|| packages.Except(allPackages).Any()))
return false;
allPackages = packages;
missingPackages = allPackages.Where(p => !HavePackage(p)).ToList();
if (currentPackage == null || !missingPackages.Contains(currentPackage))
BeginDownload();
else
missingPackages.Remove(currentPackage);
return true;
}
class Chunk { public int Index = 0; public int Count = 0; public string Data = ""; }
public static void ReceiveChunk(string data)
{
var c = new Chunk();
FieldLoader.Load(c, new MiniYaml(null, MiniYaml.FromString(data)));
var bytes = Convert.FromBase64String(c.Data);
content.Write(bytes, 0, bytes.Length);
Fraction = (float)c.Index / c.Count;
if (c.Index == c.Count - 1)
EndDownload();
}
static void BeginDownload()
{
if (missingPackages.Count == 0) // we're finished downloading resources!
{
currentPackage = null;
return;
}
currentPackage = missingPackages[0];
missingPackages.RemoveAt(0);
content = new MemoryStream();
Game.chat.AddLine(Color.White, "Debug", "Requesting package: {0}".F(currentPackage));
Game.IssueOrder(
new Order("RequestFile", null, currentPackage) { IsImmediate = true });
Fraction = 0f;
}
static void EndDownload()
{
// commit this data to disk
var parts = currentPackage.Split(':');
File.WriteAllBytes(parts[0], content.ToArray());
if (CalculateSHA1(parts[0]) != parts[1])
throw new InvalidOperationException("Broken download");
Game.chat.AddLine(Color.White, "Debug", "Finished receiving package: {0}".F(currentPackage));
currentPackage = null;
BeginDownload();
}
public static bool IsIdle()
{
return currentPackage == null
&& missingPackages.Count == 0;
}
static bool HavePackage(string p)
{
var parts = p.Split(':');
if (!File.Exists(parts[0]))
{
Game.chat.AddLine(Color.White, "Debug", "Missing package: {0}".F(p));
return false;
}
if (CalculateSHA1(parts[0]) != parts[1])
{
Game.chat.AddLine(Color.White, "Debug", "Bad SHA1 for package; redownloading: {0}".F(p));
return false;
}
Game.chat.AddLine(Color.White, "Debug", "Verified package: {0}".F(p));
return true;
}
public static string CalculateSHA1(string filename)
{
using (var csp = SHA1.Create())
return new string(csp.ComputeHash(File.ReadAllBytes(filename))
.SelectMany(a => a.ToString("x2")).ToArray());
}
}
}

226
OpenRA.Game/PathFinder.cs Normal file
View File

@@ -0,0 +1,226 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using OpenRA.Support;
using OpenRA.Traits;
namespace OpenRA
{
public class PathFinder
{
readonly World world;
float[][,] passableCost = new float[4][,];
public PathFinder( World world )
{
this.world = world;
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++)
passableCost[(int)umt] = new float[128, 128];
for( int x = 0 ; x < 128 ; x++ )
for( int y = 0 ; y < 128 ; y++ )
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++ )
passableCost[(int)umt][ x, y ] = ( world.Map.IsInMap( x, y ) )
? (float)TerrainCosts.Cost( umt, world.TileSet.GetWalkability( world.Map.MapTiles[ x, y ] ) )
: float.PositiveInfinity;
}
public List<int2> FindUnitPath( int2 from, int2 target, UnitMovementType umt )
{
using (new PerfSample("find_unit_path"))
{
var pb = FindBidiPath(
PathSearch.FromPoint(world, target, from, umt, false).WithCustomBlocker(AvoidUnitsNear(from, 4)),
PathSearch.FromPoint(world, from, target, umt, false).WithCustomBlocker(AvoidUnitsNear(from, 4)));
CheckSanePath2(pb, from, target);
return pb;
}
}
public List<int2> FindUnitPathToRange( int2 src, int2 target, UnitMovementType umt, int range )
{
using( new PerfSample( "find_unit_path_multiple_src" ) )
{
var tilesInRange = world.FindTilesInCircle(target, range)
.Where( t => world.IsCellBuildable( t, umt ) );
var path = FindPath( PathSearch.FromPoints( world, tilesInRange, src, umt, false ).WithCustomBlocker(AvoidUnitsNear(src, 4)));
path.Reverse();
return path;
}
}
public Func<int2, bool> AvoidUnitsNear(int2 p, int dist)
{
return q =>
p != q &&
((p - q).LengthSquared < dist * dist) &&
(world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(q).Any());
}
public List<int2> FindPath( PathSearch search )
{
using (new PerfSample("find_path_inner"))
{
while (!search.queue.Empty)
{
var p = search.Expand( world, passableCost );
PerfHistory.Increment("nodes_expanded", .01);
if (search.heuristic(p) == 0)
return MakePath(search.cellInfo, p);
}
// no path exists
return new List<int2>();
}
}
static List<int2> MakePath( CellInfo[ , ] cellInfo, int2 destination )
{
List<int2> ret = new List<int2>();
int2 pathNode = destination;
while( cellInfo[ pathNode.X, pathNode.Y ].Path != pathNode )
{
ret.Add( pathNode );
pathNode = cellInfo[ pathNode.X, pathNode.Y ].Path;
}
ret.Add(pathNode);
CheckSanePath(ret);
return ret;
}
List<int2> FindBidiPath( /* searches from both ends toward each other */
PathSearch fromSrc,
PathSearch fromDest)
{
while (!fromSrc.queue.Empty && !fromDest.queue.Empty)
{
/* make some progress on the first search */
var p = fromSrc.Expand( world, passableCost );
if (fromDest.cellInfo[p.X, p.Y].Seen && fromDest.cellInfo[p.X, p.Y].MinCost < float.PositiveInfinity)
return MakeBidiPath(fromSrc, fromDest, p);
/* make some progress on the second search */
var q = fromDest.Expand( world, passableCost );
if (fromSrc.cellInfo[q.X, q.Y].Seen && fromSrc.cellInfo[q.X, q.Y].MinCost < float.PositiveInfinity)
return MakeBidiPath(fromSrc, fromDest, q);
}
return new List<int2>();
}
static List<int2> MakeBidiPath(PathSearch a, PathSearch b, int2 p)
{
var ca = a.cellInfo;
var cb = b.cellInfo;
var ret = new List<int2>();
var q = p;
while (ca[q.X, q.Y].Path != q)
{
ret.Add( q );
q = ca[ q.X, q.Y ].Path;
}
ret.Add(q);
ret.Reverse();
q = p;
while (cb[q.X, q.Y].Path != q)
{
q = cb[q.X, q.Y].Path;
ret.Add(q);
}
CheckSanePath( ret );
return ret;
}
[Conditional( "SANITY_CHECKS" )]
static void CheckSanePath( List<int2> path )
{
if( path.Count == 0 )
return;
var prev = path[ 0 ];
for( int i = 0 ; i < path.Count ; i++ )
{
var d = path[ i ] - prev;
if( Math.Abs( d.X ) > 1 || Math.Abs( d.Y ) > 1 )
throw new InvalidOperationException( "(PathFinder) path sanity check failed" );
prev = path[ i ];
}
}
[Conditional("SANITY_CHECKS")]
static void CheckSanePath2(List<int2> path, int2 src, int2 dest)
{
if (path.Count == 0)
return;
if (path[0] != dest)
throw new InvalidOperationException("(PathFinder) sanity check failed: doesn't go to dest");
if (path[path.Count - 1] != src)
throw new InvalidOperationException("(PathFinder) sanity check failed: doesn't come from src");
}
}
public struct CellInfo
{
public float MinCost;
public int2 Path;
public bool Seen;
public CellInfo( float minCost, int2 path, bool seen )
{
MinCost = minCost;
Path = path;
Seen = seen;
}
}
public struct PathDistance : IComparable<PathDistance>
{
public float EstTotal;
public int2 Location;
public PathDistance(float estTotal, int2 location)
{
EstTotal = estTotal;
Location = location;
}
public int CompareTo(PathDistance other)
{
return Math.Sign(EstTotal - other.EstTotal);
}
}
}

183
OpenRA.Game/PathSearch.cs Executable file
View File

@@ -0,0 +1,183 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public class PathSearch
{
public CellInfo[ , ] cellInfo;
public PriorityQueue<PathDistance> queue;
public Func<int2, float> heuristic;
public UnitMovementType umt;
Func<int2, bool> customBlock;
public bool checkForBlocked;
public Actor ignoreBuilding;
public PathSearch()
{
cellInfo = InitCellInfo();
queue = new PriorityQueue<PathDistance>();
}
public PathSearch WithCustomBlocker(Func<int2, bool> customBlock)
{
this.customBlock = customBlock;
return this;
}
public PathSearch WithIgnoredBuilding(Actor b)
{
ignoreBuilding = b;
return this;
}
public int2 Expand( World world, float[][ , ] passableCost )
{
var p = queue.Pop();
cellInfo[ p.Location.X, p.Location.Y ].Seen = true;
var custom2 = world.customTerrain[p.Location.X, p.Location.Y];
var thisCost = (custom2 != null)
? custom2.GetCost(p.Location, umt)
: passableCost[(int)umt][p.Location.X, p.Location.Y];
if (thisCost == float.PositiveInfinity)
return p.Location;
foreach( int2 d in directions )
{
int2 newHere = p.Location + d;
if (!world.Map.IsInMap(newHere.X, newHere.Y)) continue;
if( cellInfo[ newHere.X, newHere.Y ].Seen )
continue;
var custom = world.customTerrain[newHere.X, newHere.Y];
var costHere = (custom != null) ? custom.GetCost(newHere, umt) : passableCost[(int)umt][newHere.X, newHere.Y];
if (costHere == float.PositiveInfinity)
continue;
if (!world.WorldActor.traits.Get<BuildingInfluence>().CanMoveHere(newHere) &&
world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(newHere) != ignoreBuilding)
continue;
if (world.Map.IsOverlaySolid(newHere))
continue;
// Replicate real-ra behavior of not being able to enter a cell if there is a mixture of crushable and uncrushable units
if (checkForBlocked && (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(newHere).Any(a => !world.IsActorPathableToCrush(a, umt))))
continue;
if (customBlock != null && customBlock(newHere))
continue;
var est = heuristic( newHere );
if( est == float.PositiveInfinity )
continue;
float cellCost = ((d.X * d.Y != 0) ? 1.414213563f : 1.0f) * costHere;
float newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost;
if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost )
continue;
cellInfo[ newHere.X, newHere.Y ].Path = p.Location;
cellInfo[ newHere.X, newHere.Y ].MinCost = newCost;
queue.Add( new PathDistance( newCost + est, newHere ) );
}
return p.Location;
}
static readonly int2[] directions =
{
new int2( -1, -1 ),
new int2( -1, 0 ),
new int2( -1, 1 ),
new int2( 0, -1 ),
new int2( 0, 1 ),
new int2( 1, -1 ),
new int2( 1, 0 ),
new int2( 1, 1 ),
};
public void AddInitialCell( World world, int2 location )
{
if (!world.Map.IsInMap(location.X, location.Y))
return;
cellInfo[ location.X, location.Y ] = new CellInfo( 0, location, false );
queue.Add( new PathDistance( heuristic( location ), location ) );
}
public static PathSearch FromPoint( World world, int2 from, int2 target, UnitMovementType umt, bool checkForBlocked )
{
var search = new PathSearch {
heuristic = DefaultEstimator( target ),
umt = umt,
checkForBlocked = checkForBlocked };
search.AddInitialCell( world, from );
return search;
}
public static PathSearch FromPoints(World world, IEnumerable<int2> froms, int2 target, UnitMovementType umt, bool checkForBlocked)
{
var search = new PathSearch
{
heuristic = DefaultEstimator(target),
umt = umt,
checkForBlocked = checkForBlocked
};
foreach (var sl in froms)
search.AddInitialCell(world, sl);
return search;
}
static CellInfo[ , ] InitCellInfo()
{
var cellInfo = new CellInfo[ 128, 128 ];
for( int x = 0 ; x < 128 ; x++ )
for( int y = 0 ; y < 128 ; y++ )
cellInfo[ x, y ] = new CellInfo( float.PositiveInfinity, new int2( x, y ), false );
return cellInfo;
}
public static Func<int2, float> DefaultEstimator( int2 destination )
{
return here =>
{
int2 d = ( here - destination ).Abs();
int diag = Math.Min( d.X, d.Y );
int straight = Math.Abs( d.X - d.Y );
return 1.5f * diag + straight;
};
}
}
}

224
OpenRA.Game/Player.cs Normal file
View File

@@ -0,0 +1,224 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public enum PowerState { Normal, Low, Critical };
public class Player
{
public Actor PlayerActor;
public int PaletteIndex;
public int Kills;
public string PlayerName;
public string InternalName;
public CountryInfo Country;
public readonly int Index;
public int Cash = 10000;
public int Ore = 0;
public int OreCapacity;
public int DisplayCash = 0;
public int PowerProvided = 0;
public int PowerDrained = 0;
public int SpawnPointIndex = 0;
public World World { get { return PlayerActor.World; } }
public static List<Tuple<string, string, Color>> PlayerColors = new List<Tuple<string, string, Color>>();
public static void ResetPlayerColorList()
{
// This is unsafe if the mapchange introduces/removes mods that defines new colors
// TODO: ensure that each player's palette index is reassigned appropriately
PlayerColors = new List<Tuple<string, string, Color>>();
}
public static void RegisterPlayerColor(string palette, string name, Color c)
{
PlayerColors.Add(new Tuple<string, string, Color>(palette, name, c));
}
public Color Color
{
get { return PlayerColors[PaletteIndex].c; }
}
public string Palette
{
get { return PlayerColors[PaletteIndex].a; }
}
public Shroud Shroud;
public Player( World world, int index, Session.Client client )
{
Shroud = new Shroud(this, world.Map);
this.PlayerActor = world.CreateActor("Player", new int2(int.MaxValue, int.MaxValue), this);
this.Index = index;
this.InternalName = "Multi{0}".F(index);
this.PaletteIndex = client != null ? client.PaletteIndex : index;
this.PlayerName = client != null ? client.Name : "Player {0}".F(index+1);
this.Country = world.GetCountries().FirstOrDefault( c => client != null && client.Country == c.Name )
?? world.GetCountries().First();
}
void UpdatePower()
{
var oldBalance = PowerProvided - PowerDrained;
PowerProvided = 0;
PowerDrained = 0;
var myBuildings = World.Queries.OwnedBy[this]
.WithTrait<Building>();
foreach (var a in myBuildings)
{
var p = a.Trait.GetPowerUsage();
if (p > 0)
PowerProvided += p;
else
PowerDrained -= p;
}
if (PowerProvided - PowerDrained < 0)
if (PowerProvided - PowerDrained != oldBalance)
GiveAdvice(PlayerActor.Info.Traits.Get<EvaAlertsInfo>().LowPower);
}
public float GetSiloFullness()
{
return (float)Ore / OreCapacity;
}
public PowerState GetPowerState()
{
if (PowerProvided >= PowerDrained) return PowerState.Normal;
if (PowerProvided > PowerDrained / 2) return PowerState.Low;
return PowerState.Critical;
}
void UpdateOreCapacity()
{
OreCapacity = World.Queries.OwnedBy[this]
.Where(a => a.traits.Contains<StoresOre>())
.Select(a => a.Info.Traits.Get<StoresOreInfo>())
.Sum(b => b.Capacity);
}
void GiveAdvice(string advice)
{
// todo: store the condition or something.
// repeat after Rules.General.SpeakDelay, as long as the condition holds.
Sound.PlayToPlayer(this, advice);
}
public void GiveCash( int num ) { Cash += num; }
public void GiveOre(int num)
{
Ore += num;
if (Ore > OreCapacity)
Ore = OreCapacity; // trim off the overflow.
if (Ore > .8 * OreCapacity)
GiveAdvice(PlayerActor.Info.Traits.Get<EvaAlertsInfo>().SilosNeeded); // silos needed
}
public bool TakeCash( int num )
{
if (Cash + Ore < num) return false;
if (Ore <= num)
{
num -= Ore;
Ore = 0;
Cash -= num;
}
else
Ore -= num;
return true;
}
const float displayCashFracPerFrame = .07f;
const int displayCashDeltaPerFrame = 37;
public void Tick()
{
UpdatePower();
UpdateOreCapacity();
Shroud.Tick( World );
var totalMoney = Cash + Ore;
var diff = Math.Abs(totalMoney - DisplayCash);
var move = Math.Min(Math.Max((int)(diff * displayCashFracPerFrame),
displayCashDeltaPerFrame), diff);
var eva = PlayerActor.Info.Traits.Get<EvaAlertsInfo>();
if (DisplayCash < totalMoney)
{
DisplayCash += move;
Sound.PlayToPlayer(this, eva.CashTickUp);
}
else if (DisplayCash > totalMoney)
{
DisplayCash -= move;
Sound.PlayToPlayer(this, eva.CashTickDown);
}
}
public void SyncFromLobby(Session.Client client)
{
if (PlayerName != client.Name)
{
Game.chat.AddLine(this, "is now known as " + client.Name);
PlayerName = client.Name;
}
if (string.IsNullOrEmpty(client.Country))
client.Country = PlayerActor.World.GetCountries().First().Name;
if (Country.Name != client.Country)
{
Game.chat.AddLine(this, "is now playing {0}".F(client.Country));
Country = PlayerActor.World.GetCountries().First(c => c.Name == client.Country);
}
if (PaletteIndex != client.PaletteIndex)
{
PaletteIndex = client.PaletteIndex;
Game.chat.AddLine(this, "has changed color to {0}".F(PlayerColors[client.PaletteIndex].b));
}
if (SpawnPointIndex != client.SpawnPoint)
{
SpawnPointIndex = client.SpawnPoint;
Game.chat.AddLine(this, "has changed spawn point to {0}".F(client.SpawnPoint));
}
}
}
}

View File

@@ -0,0 +1,37 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("OpenRA")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OpenRA")]
[assembly: AssemblyCopyright("Copyright © 2007,2009,2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

94
OpenRA.Game/Selection.cs Normal file
View File

@@ -0,0 +1,94 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA
{
public class Selection
{
List<Actor> actors = new List<Actor>();
public void Combine(World world, IEnumerable<Actor> newSelection, bool isCombine, bool isClick)
{
var oldSelection = actors.AsEnumerable();
if (isClick)
{
var adjNewSelection = newSelection.Take(1); /* todo: select BEST, not FIRST */
actors = (isCombine ? oldSelection.SymmetricDifference(adjNewSelection) : adjNewSelection).ToList();
}
else
actors = (isCombine ? oldSelection.Union(newSelection) : newSelection).ToList();
var voicedUnit = actors.FirstOrDefault(a => a.traits.Contains<Unit>() && a.Owner == world.LocalPlayer);
Sound.PlayVoice("Select", voicedUnit);
foreach (var ns in world.WorldActor.traits.WithInterface<INotifySelection>())
ns.SelectionChanged();
}
public IEnumerable<Actor> Actors { get { return actors; } }
public void Clear() { actors = new List<Actor>(); }
public void Tick(World world)
{
actors.RemoveAll(a => !a.IsInWorld);
}
Cache<int, List<Actor>> controlGroups = new Cache<int, List<Actor>>(_ => new List<Actor>());
public void DoControlGroup(World world, int group, Modifiers mods)
{
if (mods.HasModifier(Modifiers.Ctrl))
{
if (actors.Count == 0)
return;
controlGroups[group].Clear();
for (var i = 0; i < 10; i++) /* all control groups */
controlGroups[i].RemoveAll(a => actors.Contains(a));
controlGroups[group].AddRange(actors);
return;
}
if (mods.HasModifier(Modifiers.Alt))
{
Game.viewport.Center(controlGroups[group]);
return;
}
Combine(world, controlGroups[group],
mods.HasModifier(Modifiers.Shift), false);
}
public int? GetControlGroupForActor(Actor a)
{
return controlGroups.Where(g => g.Value.Contains(a))
.Select(g => (int?)g.Key)
.FirstOrDefault();
}
}
}

232
OpenRA.Game/Shroud.cs Normal file
View File

@@ -0,0 +1,232 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA
{
public class Shroud
{
bool[,] explored = new bool[128, 128];
Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow");
Sprite[,] sprites = new Sprite[128, 128];
bool dirty = true;
bool hasGPS = false;
Player owner;
Map map;
public Rectangle? bounds;
public Shroud(Player owner, Map map) { this.owner = owner; this.map = map; }
int gapOpaqueTicks = (int)(Rules.General.GapRegenInterval * 25 * 60);
int gapTicks;
int[,] gapField = new int[128, 128];
bool[,] gapActive = new bool[128, 128];
public bool HasGPS
{
get { return hasGPS; }
set { hasGPS = value; dirty = true;}
}
public void Tick( World world )
{
if (gapTicks > 0) { --gapTicks; return; }
// Clear active flags
gapActive = new bool[128, 128];
foreach (var a in world.Queries.WithTrait<GeneratesGap>().Where(a => owner != a.Actor.Owner))
foreach (var t in a.Trait.GetShroudedTiles())
{
gapActive[t.X, t.Y] = true;
explored[t.X, t.Y] = false;
dirty = true;
}
gapTicks = gapOpaqueTicks;
}
public bool IsExplored(int2 xy) { return IsExplored(xy.X, xy.Y); }
public bool IsExplored(int x, int y)
{
if (gapField[ x, y ] > 0)
return false;
if (hasGPS)
return true;
return explored[ x, y ];
}
public bool DisplayOnRadar(int x, int y)
{
// Active gap is never shown on radar, even if a unit is in range
if (gapActive[x , y])
return false;
return IsExplored(x,y);
}
Rectangle MakeRect(int2 center, int range)
{
return new Rectangle(center.X - range, center.Y - range, 2 * range + 1, 2 * range + 1);
}
public void Explore(World w, int2 center, int range)
{
if (range == 0)
return;
var box = MakeRect(center, range);
bounds = bounds.HasValue ?
Rectangle.Union(bounds.Value, box) : box;
foreach (var t in w.FindTilesInCircle(center, range))
{
explored[t.X, t.Y] = true;
gapField[t.X, t.Y] = 0;
}
dirty = true;
}
public void Explore(Actor a)
{
var sight = a.Info.Traits.Get<OwnedActorInfo>().Sight;
// Buildings: explore from each cell in the footprint
if (a.Info.Traits.Contains<BuildingInfo>())
{
var bi = a.Info.Traits.Get<BuildingInfo>();
foreach (var t in Footprint.Tiles(a.Info.Name, bi, a.Location))
Explore(a.World, t, sight);
}
else
{
var mobile = a.traits.GetOrDefault<Mobile>();
if (mobile != null)
{
Explore(a.World, mobile.fromCell, sight);
Explore(a.World, mobile.toCell, sight);
}
else
Explore(a.World,
(1f / Game.CellSize * a.CenterLocation).ToInt2(),
sight);
}
}
static readonly byte[][] SpecialShroudTiles =
{
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 },
new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 },
new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 },
new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 },
new byte[] { 44 },
new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 },
new byte[] { 40 },
new byte[] { 35, 24, 17, 18 },
new byte[] { 39, 39, 29, 29 },
new byte[] { 45 },
new byte[] { 43 },
new byte[] { 38, 28 },
new byte[] { 42 },
new byte[] { 41 },
new byte[] { 46 },
};
Sprite ChooseShroud(int i, int j)
{
if( !IsExplored( i, j ) ) return shadowBits[ 0xf ];
// bits are for unexploredness: up, right, down, left
var v = 0;
// bits are for unexploredness: TL, TR, BR, BL
var u = 0;
if( !IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; }
if( !IsExplored( i + 1, j ) ) { v |= 2; u |= 6; }
if( !IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; }
if( !IsExplored( i - 1, j ) ) { v |= 8; u |= 9; }
var uSides = u;
if( !IsExplored( i - 1, j - 1 ) ) u |= 1;
if( !IsExplored( i + 1, j - 1 ) ) u |= 2;
if( !IsExplored( i + 1, j + 1 ) ) u |= 4;
if( !IsExplored( i - 1, j + 1 ) ) u |= 8;
return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ];
}
internal void Draw(SpriteRenderer r)
{
if (dirty)
{
dirty = false;
for (int j = map.YOffset; j < map.YOffset + map.Height; j++)
for (int i = map.XOffset; i < map.XOffset + map.Width; i++)
sprites[i, j] = ChooseShroud(i, j);
}
var miny = bounds.HasValue ? Math.Max(map.YOffset, bounds.Value.Top) : map.YOffset;
var maxy = bounds.HasValue ? Math.Min(map.YOffset + map.Height, bounds.Value.Bottom) : map.YOffset + map.Height;
var minx = bounds.HasValue ? Math.Max(map.XOffset, bounds.Value.Left) : map.XOffset;
var maxx = bounds.HasValue ? Math.Min(map.XOffset + map.Width, bounds.Value.Right) : map.XOffset + map.Width;
for (var j = miny; j < maxy; j++)
{
var starti = minx;
for (var i = minx; i < maxx; i++)
{
if (sprites[i, j] == shadowBits[0x0f])
continue;
if (starti != i)
{
r.DrawSprite(sprites[starti,j],
Game.CellSize * new float2(starti, j),
"shroud",
new float2(Game.CellSize * (i - starti), Game.CellSize));
starti = i+1;
}
r.DrawSprite(sprites[i, j],
Game.CellSize * new float2(i, j),
"shroud");
starti = i+1;
}
if (starti < maxx)
r.DrawSprite(sprites[starti, j],
Game.CellSize * new float2(starti, j),
"shroud",
new float2(Game.CellSize * (maxx - starti), Game.CellSize));
}
}
}
}

67
OpenRA.Game/Smudge.cs Normal file
View File

@@ -0,0 +1,67 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using OpenRA.FileFormats;
using OpenRA.GameRules;
namespace OpenRA
{
static class Smudge
{
const int firstScorch = 19;
const int firstCrater = 25;
const int framesPerCrater = 5;
public static void AddSmudge(this Map map, bool isCrater, int x, int y)
{
var smudge = map.MapTiles[x, y].smudge;
if (smudge == 0)
map.MapTiles[x, y].smudge = (byte) (isCrater
? (firstCrater + framesPerCrater * ChooseSmudge())
: (firstScorch + ChooseSmudge()));
if (smudge < firstCrater || !isCrater) return; /* bib or scorch; don't change */
/* deepen the crater */
var amount = (smudge - firstCrater) % framesPerCrater;
if (amount < framesPerCrater - 1)
map.MapTiles[x, y].smudge++;
}
public static void AddSmudge(this Map map, int2 targetTile, WarheadInfo warhead)
{
switch (warhead.Explosion) /* todo: push the scorch/crater behavior into data */
{
case 4:
case 5:
map.AddSmudge(true, targetTile.X, targetTile.Y);
break;
case 3:
case 6:
map.AddSmudge(false, targetTile.X, targetTile.Y);
break;
}
}
static int lastSmudge = 0;
static int ChooseSmudge() { lastSmudge = (lastSmudge + 1) % 6; return lastSmudge; }
}
}

281
OpenRA.Game/Sound.cs Normal file
View File

@@ -0,0 +1,281 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.FileFormats;
using OpenRA.Support;
using OpenRA.Traits;
using Tao.OpenAl;
namespace OpenRA
{
public static class Sound
{
static ISoundEngine soundEngine;
static Cache<string, ISoundSource> sounds;
static ISound music;
//TODO: read these from somewhere?
static float soundVolume;
static float musicVolume;
// static bool paused;
static ISoundSource LoadSound(string filename)
{
var data = AudLoader.LoadSound(FileSystem.Open(filename));
return soundEngine.AddSoundSourceFromMemory(data, 1, 16, 22050);
}
public static void Initialize()
{
soundEngine = new OpenAlSoundEngine();
sounds = new Cache<string, ISoundSource>(LoadSound);
music = null;
soundVolume = soundEngine.Volume;
musicVolume = soundEngine.Volume;
}
public static void Play(string name)
{
if (name == "" || name == null)
return;
var sound = sounds[name];
// todo: positioning
soundEngine.Play2D(sound, false);
}
public static void PlayToPlayer(Player player, string name)
{
if( player == player.World.LocalPlayer )
Play( name );
}
public static void PlayMusic(string name)
{
var sound = sounds[name];
music = soundEngine.Play2D(sound, true);
music.Volume = musicVolume;
}
//public static bool Paused
//{
// get { return paused; }
// set { paused = value; soundEngine.SetAllSoundsPaused(paused); }
//}
public static float Volume
{
get { return soundVolume; }
set
{
soundVolume = value;
soundEngine.Volume = value;
}
}
public static float MusicVolume
{
get { return musicVolume; }
set
{
musicVolume = value;
if (music != null)
music.Volume = value;
}
}
//public static void SeekMusic(uint delta)
//{
// if (music != null)
// {
// music.PlayPosition += delta;
// if (music.PlayPosition < 0 || music.PlayPosition > music.PlayLength)
// music.PlayPosition = 0;
// }
//}
public static void PlayVoice(string phrase, Actor voicedUnit)
{
if (voicedUnit == null) return;
var mi = voicedUnit.Info.Traits.GetOrDefault<SelectableInfo>();
if (mi == null) return;
var vi = Rules.VoiceInfo[mi.Voice];
var clip = vi.Pools.Value[phrase].GetNext();
if (clip == null)
return;
if (clip.Contains(".")) /* no variants! */
{
Play(clip);
return;
}
// todo: fix this
var variants = (voicedUnit.Owner.Country.Race == "allies")
? vi.AlliedVariants : vi.SovietVariants;
var variant = variants[voicedUnit.ActorID % variants.Length];
Play(clip + variant);
}
}
interface ISoundEngine
{
ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate);
ISound Play2D(ISoundSource sound, bool loop);
float Volume { get; set; }
}
interface ISoundSource {}
interface ISound
{
float Volume { get; set; }
}
class OpenAlSoundEngine : ISoundEngine
{
float volume = 1f;
Dictionary<int, bool> sourcePool = new Dictionary<int, bool>();
const int POOL_SIZE = 32;
public OpenAlSoundEngine()
{
//var str = Alc.alcGetString(IntPtr.Zero, Alc.ALC_DEFAULT_DEVICE_SPECIFIER);
var dev = Alc.alcOpenDevice(null);
if (dev == IntPtr.Zero)
throw new InvalidOperationException("Can't create OpenAL device");
var ctx = Alc.alcCreateContext(dev, IntPtr.Zero);
if (ctx == IntPtr.Zero)
throw new InvalidOperationException("Can't create OpenAL context");
Alc.alcMakeContextCurrent(ctx);
for (var i = 0; i < POOL_SIZE; i++)
{
var source = 0;
Al.alGenSources(1, out source);
if (0 != Al.alGetError())
throw new InvalidOperationException("failed generating source {0}".F(i));
sourcePool.Add(source, false);
}
}
int GetSourceFromPool()
{
foreach (var kvp in sourcePool)
{
if (!kvp.Value)
{
sourcePool[kvp.Key] = true;
return kvp.Key;
}
}
List<int> freeSources = new List<int>();
foreach (int key in sourcePool.Keys)
{
int state;
Al.alGetSourcei(key, Al.AL_SOURCE_STATE, out state);
if (state != Al.AL_PLAYING)
freeSources.Add(key);
}
if (freeSources.Count == 0)
return -1;
foreach (int i in freeSources)
sourcePool[i] = false;
sourcePool[freeSources[0]] = true;
return freeSources[0];
}
public ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate)
{
return new OpenAlSoundSource(data, channels, sampleBits, sampleRate);
}
public ISound Play2D(ISoundSource sound, bool loop)
{
int source = GetSourceFromPool();
return new OpenAlSound(source, (sound as OpenAlSoundSource).buffer, loop);
}
public float Volume
{
get { return volume; }
set { Al.alListenerf(Al.AL_GAIN, volume = value); }
}
}
class OpenAlSoundSource : ISoundSource
{
public readonly int buffer;
static int MakeALFormat(int channels, int bits)
{
if (channels == 1)
return bits == 16 ? Al.AL_FORMAT_MONO16 : Al.AL_FORMAT_MONO8;
else
return bits == 16 ? Al.AL_FORMAT_STEREO16 : Al.AL_FORMAT_STEREO8;
}
public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate)
{
Al.alGenBuffers(1, out buffer);
Al.alBufferData(buffer, MakeALFormat(channels, sampleBits), data, data.Length, sampleRate);
}
}
class OpenAlSound : ISound
{
public readonly int source = -1;
float volume = 1f;
public OpenAlSound(int source, int buffer, bool looping)
{
if (source == -1) return;
this.source = source;
Al.alSourcef(source, Al.AL_PITCH, 1f);
Al.alSourcef(source, Al.AL_GAIN, 1f);
Al.alSource3f(source, Al.AL_POSITION, 0f, 0f, 0f);
Al.alSource3f(source, Al.AL_VELOCITY, 0f, 0f, 0f);
Al.alSourcei(source, Al.AL_BUFFER, buffer);
Al.alSourcei(source, Al.AL_LOOPING, looping ? Al.AL_TRUE : Al.AL_FALSE);
Al.alSourcePlay(source);
}
public float Volume
{
get { return volume; }
set
{
if (source != -1)
Al.alSourcef(source, Al.AL_GAIN, volume = value);
}
}
}
}

View File

@@ -0,0 +1,141 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA.Support
{
static class PerfHistory
{
static readonly Color[] colors = { Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Orange, Color.Fuchsia, Color.Lime, Color.LightBlue, Color.White, Color.Black };
static int nextColor;
public static Cache<string, PerfItem> items = new Cache<string, PerfItem>(
s =>
{
var x = new PerfItem(s, colors[nextColor++]);
if (nextColor >= colors.Length) nextColor = 0;
return x;
});
public static void Increment( string item, double x )
{
items[item].val += x;
}
public static void Tick()
{
foreach (var item in items.Values)
if (item.hasNormalTick)
item.Tick();
}
public static void Render(Renderer r, LineRenderer lr)
{
float2 origin = Game.viewport.Location + new float2(330, Game.viewport.Height - 30);
float2 basis = new float2(-3, -3);
lr.DrawLine(origin, origin + new float2(100, 0) * basis, Color.White, Color.White);
lr.DrawLine(origin + new float2(100,0) * basis, origin + new float2(100,70) * basis, Color.White, Color.White);
foreach (var item in items.Values)
{
int n = 0;
item.Samples().Aggregate((a, b) =>
{
lr.DrawLine(
origin + new float2(n, (float)a) * basis,
origin + new float2(n+1, (float)b) * basis,
item.c, item.c);
++n;
return b;
});
}
lr.Flush();
}
}
class PerfItem
{
public readonly Color c;
public readonly string Name;
public double[] samples = new double[100];
public double val = 0.0;
int head = 1, tail = 0;
public bool hasNormalTick = true;
public PerfItem(string name, Color c)
{
Name = name;
this.c = c;
}
public void Tick()
{
samples[head++] = val;
if (head == samples.Length) head = 0;
if (head == tail && ++tail == samples.Length) tail = 0;
val = 0.0;
}
public IEnumerable<double> Samples()
{
int n = head;
while (n != tail)
{
--n;
if (n < 0) n = samples.Length - 1;
yield return samples[n];
}
}
public double LastValue
{
get
{
int n = head;
if (--n < 0) n = samples.Length - 1;
return samples[n];
}
}
}
class PerfSample : IDisposable
{
readonly Stopwatch sw = new Stopwatch();
readonly string Item;
public PerfSample(string item)
{
Item = item;
}
public void Dispose()
{
PerfHistory.Increment(Item, sw.ElapsedTime() * 1000);
}
}
}

View File

@@ -0,0 +1,54 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Diagnostics;
namespace OpenRA
{
static class Program
{
[STAThread]
static void Main( string[] args )
{
if( Debugger.IsAttached )
{
Run( args );
return;
}
try
{
Run( args );
}
catch( Exception e )
{
Log.Write( "{0}", e.ToString() );
throw;
}
}
static void Run( string[] args )
{
Game.PreInit( new Settings( args ) );
Game.Run();
}
}
}

View File

@@ -0,0 +1,67 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace OpenRA
{
public class Settings
{
Dictionary<string, string> settings = new Dictionary<string, string>();
public Settings(IEnumerable<string> src)
{
Regex regex = new Regex("([^=]+)=(.*)");
foreach (string s in src)
{
Match m = regex.Match(s);
if (m == null || !m.Success)
continue;
settings.Add(m.Groups[1].Value, m.Groups[2].Value);
}
}
public bool Contains(string key) { return settings.ContainsKey(key); }
public string GetValue(string key, string defaultValue) { return Contains(key) ? settings[key] : defaultValue; }
public int GetValue(string key, int defaultValue)
{
int result;
if (!int.TryParse(GetValue(key, defaultValue.ToString()), out result))
result = defaultValue;
return result;
}
public bool GetValue(string key, bool defaultValue)
{
bool result;
if (!bool.TryParse(GetValue(key, defaultValue.ToString()), out result))
result = defaultValue;
return result;
}
}
}

125
OpenRA.Game/Sync.cs Executable file
View File

@@ -0,0 +1,125 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using OpenRA.FileFormats;
namespace OpenRA
{
public class SyncAttribute : Attribute { }
static class Sync
{
static Cache<Type, Func<object, int>> hashFuncCache = new Cache<Type, Func<object, int>>( t => GenerateHashFunc( t ) );
public static int CalculateSyncHash( object obj )
{
return hashFuncCache[ obj.GetType() ]( obj );
}
public static Func<object,int> GenerateHashFunc( Type t )
{
var d = new DynamicMethod( "hash_{0}".F( t.Name ), typeof( int ), new Type[] { typeof( object ) }, t );
var il = d.GetILGenerator();
var this_ = il.DeclareLocal( t ).LocalIndex;
il.Emit( OpCodes.Ldarg_0 );
il.Emit( OpCodes.Castclass, t );
il.Emit( OpCodes.Stloc, this_ );
il.Emit( OpCodes.Ldc_I4_0 );
const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
foreach( var field in t.GetFields( bf ).Where( x => x.GetCustomAttributes( typeof( SyncAttribute ), true ).Length != 0 ) )
{
il.Emit( OpCodes.Ldloc, this_ );
il.Emit( OpCodes.Ldfld, field );
if( field.FieldType == typeof( int ) )
{
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( bool ) )
{
var l = il.DefineLabel();
il.Emit( OpCodes.Ldc_I4, 0xaaa );
il.Emit( OpCodes.Brtrue, l );
il.Emit( OpCodes.Pop );
il.Emit( OpCodes.Ldc_I4, 0x555 );
il.MarkLabel( l );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( int2 ) )
{
il.EmitCall( OpCodes.Call, ( (Func<int2, int>)hash_int2 ).Method, null );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( TypeDictionary ) )
{
il.EmitCall( OpCodes.Call, ( (Func<TypeDictionary, int>)hash_tdict ).Method, null );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( Actor ) )
{
il.EmitCall( OpCodes.Call, ( (Func<Actor, int>)hash_actor ).Method, null );
il.Emit( OpCodes.Xor );
}
else if( field.FieldType == typeof( Player ) )
{
il.EmitCall( OpCodes.Call, ( (Func<Player, int>)hash_player ).Method, null );
il.Emit( OpCodes.Xor );
}
else
throw new NotImplementedException( "SyncAttribute on unhashable field" );
}
il.Emit( OpCodes.Ret );
return (Func<object,int>)d.CreateDelegate( typeof( Func<object,int> ) );
}
internal static int hash_int2( int2 i2 )
{
return ( ( i2.X * 5 ) ^ ( i2.Y * 3 ) ) / 4;
}
internal static int hash_tdict( TypeDictionary d )
{
int ret = 0;
foreach( var o in d )
ret += CalculateSyncHash( o );
return ret;
}
internal static int hash_actor( Actor a )
{
if( a != null )
return (int)( a.ActorID << 16 );
return 0;
}
internal static int hash_player( Player p )
{
if( p != null )
return p.Index * 0x567;
return 0;
}
}
}

View File

@@ -0,0 +1,73 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using OpenRA.Graphics;
namespace OpenRA
{
public enum UnitMovementType : byte
{
Foot = 0,
Track = 1,
Wheel = 2,
Float = 3,
Fly = 4,
}
enum TerrainMovementType : byte
{
Clear = 0,
Water = 1,
Road = 2,
Rock = 3,
//Tree = 4,
River = 5,
Rough = 6,
Wall = 7,
Beach = 8,
Ore = 9,
Special = 10,
}
static class TerrainCosts
{
static float[][] costs = Util.MakeArray<float[]>(4,
a => Util.MakeArray<float>(11, b => float.PositiveInfinity));
static TerrainCosts()
{
for( int i = 0 ; i < 11 ; i++ )
{
if( i == 4 ) continue;
var section = Rules.AllRules.GetSection( ( (TerrainMovementType)i ).ToString() );
for( int j = 0 ; j < 4 ; j++ )
{
string val = section.GetValue( ( (UnitMovementType)j ).ToString(), "0%" );
costs[j][i] = 100f / float.Parse(val.Substring(0, val.Length - 1));
}
}
}
public static float Cost( UnitMovementType unitMovementType, int r )
{
return costs[ (byte)unitMovementType ][ r ];
}
}
}

View File

@@ -0,0 +1,75 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
using OpenRA.Traits.Activities;
namespace OpenRA.Traits
{
class AutoHealInfo : StatelessTraitInfo<AutoHeal> { }
class AutoHeal : ITick
{
void AttackTarget(Actor self, Actor target)
{
var attack = self.traits.Get<AttackBase>();
if (target != null)
attack.ResolveOrder(self, new Order("Attack", self, target));
else
if (self.GetCurrentActivity() is Attack)
self.CancelActivity();
}
bool NeedsNewTarget(Actor self)
{
var attack = self.traits.Get<AttackBase>();
var range = Util.GetMaximumRange(self);
if (attack.target == null)
return true; // he's dead.
if ((attack.target.Location - self.Location).LengthSquared > range * range + 2)
return true; // wandered off faster than we could follow
if (attack.target.Health == attack.target.Info.Traits.Get<OwnedActorInfo>().HP)
return true; // fully healed
return false;
}
public void Tick(Actor self)
{
var range = Util.GetMaximumRange(self);
if (NeedsNewTarget(self))
AttackTarget(self, ChooseTarget(self, range));
}
Actor ChooseTarget(Actor self, float range)
{
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
return inRange
.Where(a => a.Owner == self.Owner && a != self) /* todo: one day deal with friendly players */
.Where(a => Combat.HasAnyValidWeapons(self, a))
.Where(a => a.Health < a.Info.Traits.Get<OwnedActorInfo>().HP)
.OrderBy(a => (a.Location - self.Location).LengthSquared)
.FirstOrDefault();
}
}
}

View File

@@ -0,0 +1,77 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
namespace OpenRA.Traits
{
class AutoTargetInfo : StatelessTraitInfo<AutoTarget> { }
class AutoTarget : ITick, INotifyDamage
{
void AttackTarget(Actor self, Actor target)
{
var attack = self.traits.Get<AttackBase>();
if (target != null)
attack.ResolveOrder(self, new Order("Attack", self, target));
}
public void Tick(Actor self)
{
if (!self.IsIdle) return;
var attack = self.traits.Get<AttackBase>();
var range = Util.GetMaximumRange(self);
if (attack.target == null ||
(attack.target.Location - self.Location).LengthSquared > range * range + 2)
AttackTarget(self, ChooseTarget(self, range));
}
Actor ChooseTarget(Actor self, float range)
{
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
return inRange
.Where(a => a.Owner != null && a.Owner != self.Owner) /* todo: one day deal with friendly players */
.Where(a => Combat.HasAnyValidWeapons(self, a))
.OrderBy(a => (a.Location - self.Location).LengthSquared)
.FirstOrDefault();
}
public void Damaged(Actor self, AttackInfo e)
{
// not a lot we can do about things we can't hurt... although maybe we should automatically run away?
if (!Combat.HasAnyValidWeapons(self, e.Attacker))
return;
if (e.Attacker.Owner == self.Owner)
return; // don't retaliate against own units force-firing on us. it's usually not what the player wanted.
if (e.Damage < 0)
return; // don't retaliate against healers
var attack = self.traits.Get<AttackBase>();
if (attack.target != null) return;
AttackTarget(self, e.Attacker);
}
}
}

View File

@@ -0,0 +1,51 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits
{
class SelfHealingInfo : ITraitInfo
{
public readonly int Step = 5;
public readonly int Ticks = 5;
public readonly float HealIfBelow = .5f;
public object Create(Actor self) { return new SelfHealing(); }
}
class SelfHealing : ITick
{
int ticks;
public void Tick(Actor self)
{
var info = self.Info.Traits.Get<SelfHealingInfo>();
if ((float)self.Health / self.GetMaxHP() >= info.HealIfBelow)
return;
if (--ticks <= 0)
{
ticks = info.Ticks;
self.InflictDamage(self, -info.Step, Rules.WarheadInfo["Super"]);
}
}
}
}

View File

@@ -0,0 +1,64 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits
{
class TakeCoverInfo : ITraitInfo
{
public object Create(Actor self) { return new TakeCover(self); }
}
// infantry prone behavior
class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier
{
const int defaultProneTime = 100; /* ticks, =4s */
const float proneDamage = .5f;
const float proneSpeed = .5f;
[Sync]
int remainingProneTime = 0;
public bool IsProne { get { return remainingProneTime > 0; } }
public TakeCover(Actor self) {}
public void Damaged(Actor self, AttackInfo e)
{
if (e.Damage > 0) /* fix to allow healing via `damage` */
remainingProneTime = defaultProneTime;
}
public void Tick(Actor self)
{
if (IsProne)
--remainingProneTime;
}
public float GetDamageModifier()
{
return IsProne ? proneDamage : 1f;
}
public float GetSpeedModifier()
{
return IsProne ? proneSpeed : 1f;
}
}
}

View File

@@ -0,0 +1,69 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
/* non-turreted attack */
class Attack : IActivity
{
Actor Target;
int Range;
public Attack(Actor target, int range)
{
Target = target;
Range = range;
}
public IActivity NextActivity { get; set; }
public IActivity Tick( Actor self )
{
var unit = self.traits.Get<Unit>();
if (Target == null || Target.IsDead)
return NextActivity;
if ((Target.Location - self.Location).LengthSquared >= Range * Range)
return new Move( Target, Range ) { NextActivity = this };
var desiredFacing = Util.GetFacing((Target.Location - self.Location).ToFloat2(), 0);
var renderUnit = self.traits.GetOrDefault<RenderUnit>();
var numDirs = (renderUnit != null)
? renderUnit.anim.CurrentSequence.Facings : 8;
if (Util.QuantizeFacing(unit.Facing, numDirs)
!= Util.QuantizeFacing(desiredFacing, numDirs))
{
return new Turn( desiredFacing ) { NextActivity = this };
}
var attack = self.traits.Get<AttackBase>();
attack.target = Target;
attack.DoAttack(self);
return this;
}
public void Cancel(Actor self)
{
Target = null;
}
}
}

View File

@@ -0,0 +1,40 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.Traits.Activities
{
public class CallFunc : IActivity
{
public CallFunc(Action a) { this.a = a; }
Action a;
public IActivity NextActivity { get; set; }
public IActivity Tick(Actor self)
{
if (a != null) a();
return NextActivity;
}
public void Cancel(Actor self) { a = null; NextActivity = null; }
}
}

View File

@@ -0,0 +1,91 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
namespace OpenRA.Traits.Activities
{
public class DeliverOre : IActivity
{
public IActivity NextActivity { get; set; }
bool isDocking;
Actor refinery;
public DeliverOre() { }
public DeliverOre( Actor refinery )
{
this.refinery = refinery;
}
public IActivity Tick( Actor self )
{
var mobile = self.traits.Get<Mobile>();
if( NextActivity != null )
return NextActivity;
if( refinery != null && refinery.IsDead )
refinery = null;
if( refinery == null || self.Location != refinery.Location + refinery.traits.Get<IAcceptOre>().DeliverOffset )
{
var search = new PathSearch
{
heuristic = PathSearch.DefaultEstimator( self.Location ),
umt = mobile.GetMovementType(),
checkForBlocked = false,
};
var refineries = self.World.Queries.OwnedBy[self.Owner]
.Where(x => x.traits.Contains<IAcceptOre>())
.ToList();
if( refinery != null )
search.AddInitialCell(self.World, refinery.Location + refinery.traits.Get<IAcceptOre>().DeliverOffset);
else
foreach( var r in refineries )
search.AddInitialCell(self.World, r.Location + r.traits.Get<IAcceptOre>().DeliverOffset);
var path = self.World.PathFinder.FindPath( search );
path.Reverse();
if( path.Count != 0 )
{
refinery = refineries.FirstOrDefault(x => x.Location + x.traits.Get<IAcceptOre>().DeliverOffset == path[0]);
return new Move( () => path ) { NextActivity = this };
}
else
// no refineries reachable?
return this;
}
else if (!isDocking)
{
isDocking = true;
refinery.traits.Get<IAcceptOre>().OnDock(self, this);
}
return this;
}
public void Cancel(Actor self)
{
// TODO: allow canceling of deliver orders?
}
}
}

View File

@@ -0,0 +1,51 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
class EnterTransport : IActivity
{
public IActivity NextActivity { get; set; }
bool isCanceled;
public Actor transport;
public EnterTransport(Actor self, Actor transport)
{
this.transport = transport;
}
public IActivity Tick(Actor self)
{
if (isCanceled) return NextActivity;
if (transport == null || !transport.IsInWorld) return NextActivity;
var cargo = transport.traits.Get<Cargo>();
if (cargo.IsFull(transport))
return NextActivity;
cargo.Load(transport, self);
self.World.AddFrameEndTask(w => w.Remove(self));
return this;
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -0,0 +1,64 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.Traits.Activities
{
public class Fly : IActivity
{
readonly float2 Pos;
bool isCanceled;
public Fly(float2 pos) { Pos = pos; }
public Fly(int2 pos) { Pos = Util.CenterOfCell(pos); }
public IActivity NextActivity { get; set; }
const int CruiseAltitude = 20;
public IActivity Tick(Actor self)
{
if (isCanceled) return NextActivity;
var d = Pos - self.CenterLocation;
if (d.LengthSquared < 50) /* close enough */
return NextActivity;
var unit = self.traits.Get<Unit>();
if (unit.Altitude < CruiseAltitude)
++unit.Altitude;
var desiredFacing = Util.GetFacing(d, unit.Facing);
if (unit.Altitude == CruiseAltitude)
Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.Traits.Get<UnitInfo>().ROT);
var speed = .2f * Util.GetEffectiveSpeed(self);
var angle = unit.Facing / 128f * Math.PI;
self.CenterLocation += speed * -float2.FromAngle((float)angle);
self.Location = ((1 / 24f) * self.CenterLocation).ToInt2();
return this;
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -0,0 +1,69 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
public class FlyAttack : IActivity
{
public IActivity NextActivity { get; set; }
Actor Target;
public FlyAttack(Actor target) { Target = target; }
public IActivity Tick(Actor self)
{
if (Target == null || Target.IsDead)
return NextActivity;
var limitedAmmo = self.traits.GetOrDefault<LimitedAmmo>();
if (limitedAmmo != null && !limitedAmmo.HasAmmo())
return NextActivity;
return Util.SequenceActivities(
new Fly(Target.CenterLocation),
new FlyTimed(50, 20),
this);
}
public void Cancel(Actor self) { Target = null; NextActivity = null; }
}
public class FlyCircle : IActivity
{
public IActivity NextActivity { get; set; }
int2 Target;
bool isCanceled;
public FlyCircle(int2 target) { Target = target; }
public IActivity Tick(Actor self)
{
if (isCanceled)
return NextActivity;
return Util.SequenceActivities(
new Fly(Util.CenterOfCell(Target)),
new FlyTimed(50, 20),
this);
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -0,0 +1,53 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.Traits.Activities
{
class FlyTimed : IActivity
{
public IActivity NextActivity { get; set; }
int remainingTicks;
int targetAltitude;
public FlyTimed(int ticks, int targetAltitude) { remainingTicks = ticks; this.targetAltitude = targetAltitude; }
public IActivity Tick(Actor self)
{
if (remainingTicks == 0)
return NextActivity;
--remainingTicks;
var unit = self.traits.Get<Unit>();
var speed = .2f * Util.GetEffectiveSpeed(self);
var angle = unit.Facing / 128f * Math.PI;
self.CenterLocation += speed * -float2.FromAngle((float)angle);
self.Location = ((1 / 24f) * self.CenterLocation).ToInt2();
unit.Altitude += Math.Sign(targetAltitude - unit.Altitude);
return this;
}
public void Cancel(Actor self) { remainingTicks = 0; NextActivity = null; }
}
}

View File

@@ -0,0 +1,54 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
class Follow : IActivity
{
Actor Target;
int Range;
public Follow(Actor target, int range)
{
Target = target;
Range = range;
}
public IActivity NextActivity { get; set; }
public IActivity Tick( Actor self )
{
if (Target == null || Target.IsDead)
return NextActivity;
var inRange = ( Target.Location - self.Location ).LengthSquared < Range * Range;
if( !inRange )
return new Move( Target, Range ) { NextActivity = this };
return this;
}
public void Cancel(Actor self)
{
Target = null;
}
}
}

View File

@@ -0,0 +1,85 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
public class Harvest : IActivity
{
public IActivity NextActivity { get; set; }
bool isHarvesting = false;
public IActivity Tick( Actor self )
{
if( isHarvesting ) return this;
if( NextActivity != null ) return NextActivity;
var harv = self.traits.Get<Harvester>();
if( harv.IsFull )
return new DeliverOre { NextActivity = NextActivity };
if (HarvestThisTile(self))
return this;
else
{
FindMoreOre(self);
return NextActivity;
}
}
bool HarvestThisTile(Actor self)
{
var harv = self.traits.Get<Harvester>();
var renderUnit = self.traits.Get<RenderUnit>(); /* better have one of these! */
var isGem = false;
if (!self.World.Map.ContainsResource(self.Location) ||
!self.World.Map.Harvest(self.Location, out isGem))
return false;
if (renderUnit.anim.CurrentSequence.Name != "harvest")
{
isHarvesting = true;
renderUnit.PlayCustomAnimation(self, "harvest", () => isHarvesting = false);
}
harv.AcceptResource(isGem);
return true;
}
void FindMoreOre(Actor self)
{
self.QueueActivity(new Move(
() =>
{
var search = new PathSearch
{
heuristic = loc => (self.World.Map.ContainsResource(loc) ? 0 : 1),
umt = UnitMovementType.Wheel,
checkForBlocked = true
};
search.AddInitialCell(self.World, self.Location);
return self.World.PathFinder.FindPath(search);
}));
self.QueueActivity(new Harvest());
}
public void Cancel(Actor self) { }
}
}

View File

@@ -0,0 +1,69 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.Traits.Activities
{
class HeliAttack : IActivity
{
Actor target;
const int CruiseAltitude = 20;
public HeliAttack( Actor target ) { this.target = target; }
public IActivity NextActivity { get; set; }
public IActivity Tick(Actor self)
{
if (target == null || target.IsDead)
return NextActivity;
var limitedAmmo = self.traits.GetOrDefault<LimitedAmmo>();
if (limitedAmmo != null && !limitedAmmo.HasAmmo())
return NextActivity;
var unit = self.traits.Get<Unit>();
if (unit.Altitude != CruiseAltitude)
{
unit.Altitude += Math.Sign(CruiseAltitude - unit.Altitude);
return this;
}
var range = self.GetPrimaryWeapon().Range - 1;
var dist = target.CenterLocation - self.CenterLocation;
var desiredFacing = Util.GetFacing(dist, unit.Facing);
Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.Traits.Get<UnitInfo>().ROT);
if (!float2.WithinEpsilon(float2.Zero, dist, range * Game.CellSize))
{
var rawSpeed = .2f * Util.GetEffectiveSpeed(self);
self.CenterLocation += (rawSpeed / dist.Length) * dist;
self.Location = ((1 / 24f) * self.CenterLocation).ToInt2();
}
/* todo: maintain seperation wrt other helis */
return this;
}
public void Cancel(Actor self) { target = null; NextActivity = null; }
}
}

View File

@@ -0,0 +1,71 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System;
namespace OpenRA.Traits.Activities
{
class HeliFly : IActivity
{
const int CruiseAltitude = 20;
readonly float2 Dest;
public HeliFly(float2 dest)
{
Dest = dest;
}
public IActivity NextActivity { get; set; }
bool isCanceled;
public IActivity Tick(Actor self)
{
if (isCanceled)
return NextActivity;
var unit = self.traits.Get<Unit>();
if (unit.Altitude != CruiseAltitude)
{
unit.Altitude += Math.Sign(CruiseAltitude - unit.Altitude);
return this;
}
var dist = Dest - self.CenterLocation;
if (float2.WithinEpsilon(float2.Zero, dist, 2))
{
self.CenterLocation = Dest;
self.Location = ((1 / 24f) * self.CenterLocation).ToInt2();
return NextActivity;
}
var desiredFacing = Util.GetFacing(dist, unit.Facing);
Util.TickFacing(ref unit.Facing, desiredFacing,
self.Info.Traits.Get<UnitInfo>().ROT);
var rawSpeed = .2f * Util.GetEffectiveSpeed(self);
self.CenterLocation += (rawSpeed / dist.Length) * dist;
self.Location = ((1 / 24f) * self.CenterLocation).ToInt2();
return this;
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -0,0 +1,47 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
class HeliLand : IActivity
{
public HeliLand(bool requireSpace) { this.requireSpace = requireSpace; }
bool requireSpace;
bool isCanceled;
public IActivity NextActivity { get; set; }
public IActivity Tick(Actor self)
{
if (isCanceled) return NextActivity;
var unit = self.traits.Get<Unit>();
if (unit.Altitude == 0)
return NextActivity;
if (requireSpace && !self.World.IsCellBuildable(self.Location, UnitMovementType.Foot))
return this; // fail to land if no space
--unit.Altitude;
return this;
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -0,0 +1,68 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
using System.Linq;
namespace OpenRA.Traits.Activities
{
class HeliReturn : IActivity
{
public IActivity NextActivity { get; set; }
bool isCanceled;
static Actor ChooseHelipad(Actor self)
{
return self.World.Queries.OwnedBy[self.Owner].FirstOrDefault(
a => a.Info.Name == "hpad" &&
!Reservable.IsReserved(a));
}
public IActivity Tick(Actor self)
{
if (isCanceled) return NextActivity;
var dest = ChooseHelipad(self);
var initialFacing = self.Info.Traits.Get<UnitInfo>().InitialFacing;
if (dest == null)
return Util.SequenceActivities(
new Turn(initialFacing),
new HeliLand(true),
NextActivity);
var res = dest.traits.GetOrDefault<Reservable>();
if (res != null)
self.traits.Get<Helicopter>().reservation = res.Reserve(self);
var pi = dest.Info.Traits.GetOrDefault<ProductionInfo>();
var offset = pi != null ? pi.SpawnOffset : null;
var offsetVec = offset != null ? new float2(offset[0], offset[1]) : float2.Zero;
return Util.SequenceActivities(
new HeliFly(dest.CenterLocation + offsetVec),
new Turn(initialFacing),
new HeliLand(false),
new Rearm(),
NextActivity);
}
public void Cancel(Actor self) { isCanceled = true; NextActivity = null; }
}
}

View File

@@ -0,0 +1,30 @@
#region Copyright & License Information
/*
* Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
* This file is part of OpenRA.
*
* OpenRA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenRA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenRA. If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
namespace OpenRA.Traits.Activities
{
class Idle : IActivity
{
public IActivity NextActivity { get; set; }
public IActivity Tick(Actor self) { return NextActivity; }
public void Cancel(Actor self) {}
}
}

Some files were not shown because too many files have changed in this diff Show More