pull chrisforbes
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.GameRules;
|
||||
using System.Collections.Generic;
|
||||
using OpenRa.Game.Effects;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class APMineInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new APMine(self); }
|
||||
}
|
||||
|
||||
class APMine : ICrushable, IOccupySpace
|
||||
{
|
||||
readonly Actor self;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.GameRules;
|
||||
using System.Collections.Generic;
|
||||
using OpenRa.Game.Effects;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ATMineInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new ATMine(self); }
|
||||
}
|
||||
|
||||
class ATMine : ICrushable, IOccupySpace
|
||||
{
|
||||
readonly Actor self;
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AcceptsOreInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new AcceptsOre(self); }
|
||||
}
|
||||
|
||||
class AcceptsOre
|
||||
{
|
||||
public AcceptsOre(Actor self)
|
||||
@@ -9,7 +14,7 @@ namespace OpenRa.Game.Traits
|
||||
Game.world.AddFrameEndTask(
|
||||
w =>
|
||||
{ /* create the free harvester! */
|
||||
var harvester = new Actor(Rules.UnitInfo["harv"], self.Location + new int2(1, 2), self.Owner);
|
||||
var harvester = new Actor("harv", self.Location + new int2(1, 2), self.Owner);
|
||||
var unit = harvester.traits.Get<Unit>();
|
||||
var mobile = harvester.traits.Get<Mobile>();
|
||||
unit.Facing = 64;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
return new Move( Target, Range ) { NextActivity = this };
|
||||
|
||||
var desiredFacing = Util.GetFacing((Target.Location - self.Location).ToFloat2(), 0);
|
||||
var renderUnit = self.traits.WithInterface<RenderUnit>().FirstOrDefault();
|
||||
var renderUnit = self.traits.GetOrDefault<RenderUnit>();
|
||||
var numDirs = (renderUnit != null)
|
||||
? renderUnit.anim.CurrentSequence.Length : 8;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
return new Turn( desiredFacing ) { NextActivity = this };
|
||||
}
|
||||
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
attack.target = Target;
|
||||
attack.DoAttack(self);
|
||||
return this;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
|
||||
if (target.Owner == self.Owner)
|
||||
{
|
||||
if (target.Health == target.Info.Strength)
|
||||
if (target.Health == target.Info.Traits.Get<OwnedActorInfo>().HP)
|
||||
return NextActivity;
|
||||
target.InflictDamage(self, -EngineerCapture.EngineerDamage, Rules.WarheadInfo["Super"]);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
else if( unit.Facing != 64 )
|
||||
return new Turn( 64 ) { NextActivity = this };
|
||||
|
||||
var renderUnit = self.traits.WithInterface<RenderUnit>().First();
|
||||
var renderUnit = self.traits.Get<RenderUnit>();
|
||||
if( renderUnit.anim.CurrentSequence.Name != "empty" )
|
||||
renderUnit.PlayCustomAnimation( self, "empty",
|
||||
() => isDone = true );
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
Sound.Play("placbldg.aud");
|
||||
Sound.Play("build5.aud");
|
||||
}
|
||||
Game.world.Add( new Actor( Rules.UnitInfo["fact"], self.Location - new int2( 1, 1 ), self.Owner ) );
|
||||
Game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) );
|
||||
} );
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
|
||||
var desiredFacing = Util.GetFacing(d, unit.Facing);
|
||||
if (unit.Altitude == CruiseAltitude)
|
||||
Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT);
|
||||
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;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
{
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var harv = self.traits.Get<Harvester>();
|
||||
var renderUnit = self.traits.WithInterface<RenderUnit>().First(); /* better have one of these! */
|
||||
var renderUnit = self.traits.Get<RenderUnit>(); /* better have one of these! */
|
||||
|
||||
var isGem = false;
|
||||
if (!Rules.Map.ContainsResource(self.Location) ||
|
||||
|
||||
@@ -30,11 +30,11 @@ namespace OpenRa.Game.Traits.Activities
|
||||
return this;
|
||||
}
|
||||
|
||||
var range = Rules.WeaponInfo[ self.Info.Primary ].Range - 1;
|
||||
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.ROT);
|
||||
Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.Traits.Get<UnitInfo>().ROT);
|
||||
|
||||
if (!float2.WithinEpsilon(float2.Zero, dist, range * Game.CellSize))
|
||||
{
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace OpenRa.Game.Traits.Activities
|
||||
}
|
||||
|
||||
var desiredFacing = Util.GetFacing(dist, unit.Facing);
|
||||
Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT);
|
||||
Util.TickFacing(ref unit.Facing, desiredFacing,
|
||||
self.Info.Traits.Get<UnitInfo>().ROT);
|
||||
|
||||
var rawSpeed = .2f * Util.GetEffectiveSpeed(self);
|
||||
self.CenterLocation += (rawSpeed / dist.Length) * dist;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
static Actor ChooseHelipad(Actor self)
|
||||
{
|
||||
return Game.world.Actors.FirstOrDefault(
|
||||
a => a.Info == Rules.UnitInfo["HPAD"] &&
|
||||
a => a.Info == Rules.NewUnitInfo["HPAD"] &&
|
||||
a.Owner == self.Owner &&
|
||||
!Reservable.IsReserved(a));
|
||||
}
|
||||
@@ -24,9 +24,11 @@ namespace OpenRa.Game.Traits.Activities
|
||||
if (isCanceled) return NextActivity;
|
||||
var dest = ChooseHelipad(self);
|
||||
|
||||
var initialFacing = self.Info.Traits.Get<UnitInfo>().InitialFacing;
|
||||
|
||||
if (dest == null)
|
||||
return Util.SequenceActivities(
|
||||
new Turn(self.Info.InitialFacing),
|
||||
new Turn(initialFacing),
|
||||
new HeliLand(true),
|
||||
NextActivity);
|
||||
|
||||
@@ -34,12 +36,13 @@ namespace OpenRa.Game.Traits.Activities
|
||||
if (res != null)
|
||||
self.traits.Get<Helicopter>().reservation = res.Reserve(self);
|
||||
|
||||
var offset = (dest.Info as BuildingInfo).SpawnOffset;
|
||||
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(self.Info.InitialFacing),
|
||||
new Turn(initialFacing),
|
||||
new HeliLand(false),
|
||||
new Rearm(),
|
||||
NextActivity);
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
--unit.Altitude;
|
||||
|
||||
var desiredFacing = Util.GetFacing(d, unit.Facing);
|
||||
Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT);
|
||||
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;
|
||||
|
||||
|
||||
@@ -16,8 +16,11 @@ namespace OpenRa.Game.Traits.Activities
|
||||
if (isCanceled) return NextActivity;
|
||||
if (remainingTicks == 0)
|
||||
{
|
||||
var costPerHp = (Rules.General.URepairPercent * self.Info.Cost) / self.Info.Strength;
|
||||
var hpToRepair = Math.Min(Rules.General.URepairStep, self.Info.Strength - self.Health);
|
||||
var unitCost = self.Info.Traits.Get<BuildableInfo>().Cost;
|
||||
var hp = self.Info.Traits.Get<OwnedActorInfo>().HP;
|
||||
|
||||
var costPerHp = (Rules.General.URepairPercent * unitCost) / hp;
|
||||
var hpToRepair = Math.Min(Rules.General.URepairStep, hp - self.Health);
|
||||
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
|
||||
if (!self.Owner.TakeCash(cost))
|
||||
{
|
||||
@@ -26,7 +29,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
}
|
||||
|
||||
self.InflictDamage(self, -hpToRepair, Rules.WarheadInfo["Super"]);
|
||||
if (self.Health == self.Info.Strength)
|
||||
if (self.Health == hp)
|
||||
return NextActivity;
|
||||
|
||||
var hostBuilding = Game.FindUnits(self.CenterLocation, self.CenterLocation)
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
Actor ChooseAirfield(Actor self)
|
||||
{
|
||||
var airfield = Game.world.Actors
|
||||
.Where(a => a.Info == Rules.UnitInfo["AFLD"] /* todo: generalize this */
|
||||
.Where(a => a.Info.Name == "afld"
|
||||
&& a.Owner == self.Owner
|
||||
&& !Reservable.IsReserved(a))
|
||||
.FirstOrDefault();
|
||||
@@ -41,7 +41,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var speed = .2f * Util.GetEffectiveSpeed(self);
|
||||
var approachStart = landPos - new float2(unit.Altitude * speed, 0);
|
||||
var turnRadius = (128f / self.Info.ROT) * speed / (float)Math.PI;
|
||||
var turnRadius = (128f / self.Info.Traits.Get<UnitInfo>().ROT) * speed / (float)Math.PI;
|
||||
|
||||
/* work out the center points */
|
||||
var fwd = -float2.FromAngle(unit.Facing / 128f * (float)Math.PI);
|
||||
|
||||
@@ -13,8 +13,9 @@ namespace OpenRa.Game.Traits.Activities
|
||||
|
||||
void DoSell(Actor self)
|
||||
{
|
||||
var refund = Rules.General.RefundPercent
|
||||
* self.Health * self.Info.Cost / self.Info.Strength;
|
||||
var cost = self.Info.Traits.Get<BuildableInfo>().Cost;
|
||||
var hp = self.Info.Traits.Get<OwnedActorInfo>().HP;
|
||||
var refund = Rules.General.RefundPercent * self.Health * cost / hp;
|
||||
|
||||
self.Owner.GiveCash((int)refund);
|
||||
self.Health = 0;
|
||||
@@ -29,7 +30,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
{
|
||||
if (!started)
|
||||
{
|
||||
var rb = self.traits.WithInterface<RenderBuilding>().First();
|
||||
var rb = self.traits.Get<RenderBuilding>();
|
||||
//var rb = self.traits.Get<RenderBuilding>();
|
||||
rb.PlayCustomAnimBackwards(self, "make",
|
||||
() => Game.world.AddFrameEndTask(w => DoSell(self)));
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
if( desiredFacing == unit.Facing )
|
||||
return NextActivity;
|
||||
|
||||
Util.TickFacing( ref unit.Facing, desiredFacing, self.Info.ROT );
|
||||
Util.TickFacing( ref unit.Facing, desiredFacing, self.Info.Traits.Get<UnitInfo>().ROT );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
ns.Sold(self);
|
||||
w.Remove(self);
|
||||
|
||||
var mcv = new Actor(Rules.UnitInfo["MCV"], self.Location + new int2(1, 1), self.Owner);
|
||||
var mcv = new Actor("mcv", self.Location + new int2(1, 1), self.Owner);
|
||||
mcv.traits.Get<Unit>().Facing = 96;
|
||||
w.Add(mcv);
|
||||
}
|
||||
|
||||
@@ -33,8 +33,9 @@ namespace OpenRa.Game.Traits.Activities
|
||||
// if we're a thing that can turn, turn to the
|
||||
// right facing for the unload animation
|
||||
var unit = self.traits.GetOrDefault<Unit>();
|
||||
if (unit != null && unit.Facing != self.Info.UnloadFacing)
|
||||
return new Turn(self.Info.UnloadFacing) { NextActivity = this };
|
||||
var unloadFacing = self.Info.Traits.Get<CargoInfo>().UnloadFacing;
|
||||
if (unit != null && unit.Facing != unloadFacing)
|
||||
return new Turn(unloadFacing) { NextActivity = this };
|
||||
|
||||
// todo: handle the BS of open/close sequences, which are inconsistent,
|
||||
// for reasons that probably make good sense to the westwood guys.
|
||||
@@ -43,7 +44,7 @@ namespace OpenRa.Game.Traits.Activities
|
||||
if (cargo.IsEmpty(self))
|
||||
return NextActivity;
|
||||
|
||||
var ru = self.traits.WithInterface<RenderUnit>().FirstOrDefault();
|
||||
var ru = self.traits.GetOrDefault<RenderUnit>();
|
||||
if (ru != null)
|
||||
ru.PlayCustomAnimation(self, "unload", null);
|
||||
|
||||
|
||||
@@ -6,6 +6,21 @@ using OpenRa.Game.Effects;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AttackBaseInfo : ITraitInfo
|
||||
{
|
||||
public readonly string PrimaryWeapon = null;
|
||||
public readonly string SecondaryWeapon = null;
|
||||
public readonly int Recoil = 0;
|
||||
public readonly int[] PrimaryLocalOffset = { };
|
||||
public readonly int[] SecondaryLocalOffset = { };
|
||||
public readonly int[] PrimaryOffset = { 0, 0 };
|
||||
public readonly int[] SecondaryOffset = null;
|
||||
public readonly bool MuzzleFlash = false;
|
||||
public readonly int FireDelay = 0;
|
||||
|
||||
public virtual object Create(Actor self) { return new AttackBase(self); }
|
||||
}
|
||||
|
||||
class AttackBase : IIssueOrder, IResolveOrder, ITick
|
||||
{
|
||||
[Sync] public Actor target;
|
||||
@@ -23,8 +38,8 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public AttackBase(Actor self)
|
||||
{
|
||||
var primaryWeapon = self.Info.Primary != null ? Rules.WeaponInfo[self.Info.Primary] : null;
|
||||
var secondaryWeapon = self.Info.Secondary != null ? Rules.WeaponInfo[self.Info.Secondary] : null;
|
||||
var primaryWeapon = self.GetPrimaryWeapon();
|
||||
var secondaryWeapon = self.GetSecondaryWeapon();
|
||||
|
||||
primaryBurst = primaryWeapon != null ? primaryWeapon.Burst : 1;
|
||||
secondaryBurst = secondaryWeapon != null ? secondaryWeapon.Burst : 1;
|
||||
@@ -73,19 +88,20 @@ namespace OpenRa.Game.Traits
|
||||
public void DoAttack(Actor self)
|
||||
{
|
||||
var unit = self.traits.GetOrDefault<Unit>();
|
||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
|
||||
if (self.Info.Primary != null && CheckFire(self, unit, self.Info.Primary, ref primaryFireDelay,
|
||||
self.Info.PrimaryOffset, ref primaryBurst, self.Info.PrimaryLocalOffset))
|
||||
if (info.PrimaryWeapon != null && CheckFire(self, unit, info.PrimaryWeapon, ref primaryFireDelay,
|
||||
info.PrimaryOffset, ref primaryBurst, info.PrimaryLocalOffset))
|
||||
{
|
||||
secondaryFireDelay = Math.Max(4, secondaryFireDelay);
|
||||
primaryRecoil = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.Info.Secondary != null && CheckFire(self, unit, self.Info.Secondary, ref secondaryFireDelay,
|
||||
self.Info.SecondaryOffset ?? self.Info.PrimaryOffset, ref secondaryBurst, self.Info.SecondaryLocalOffset))
|
||||
if (info.SecondaryWeapon != null && CheckFire(self, unit, info.SecondaryWeapon, ref secondaryFireDelay,
|
||||
info.SecondaryOffset ?? info.PrimaryOffset, ref secondaryBurst, info.SecondaryLocalOffset))
|
||||
{
|
||||
if (self.Info.SecondaryOffset != null) secondaryRecoil = 1;
|
||||
if (info.SecondaryOffset != null) secondaryRecoil = 1;
|
||||
else primaryRecoil = 1;
|
||||
return;
|
||||
}
|
||||
@@ -126,8 +142,9 @@ namespace OpenRa.Game.Traits
|
||||
var firePos = self.CenterLocation.ToInt2() + Util.GetTurretPosition(self, unit, fireOffset, 0f).ToInt2();
|
||||
var thisTarget = target; // closure.
|
||||
var destUnit = thisTarget.traits.GetOrDefault<Unit>();
|
||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
|
||||
ScheduleDelayedAction(self.Info.FireDelay, () =>
|
||||
ScheduleDelayedAction(info.FireDelay, () =>
|
||||
{
|
||||
var srcAltitude = unit != null ? unit.Altitude : 0;
|
||||
var destAltitude = destUnit != null ? destUnit.Altitude : 0;
|
||||
@@ -140,11 +157,11 @@ namespace OpenRa.Game.Traits
|
||||
var fireFacing = thisLocalOffset.ElementAtOrDefault(2) +
|
||||
(self.traits.Contains<Turreted>() ? self.traits.Get<Turreted>().turretFacing : unit.Facing);
|
||||
|
||||
Game.world.Add(new Missile(weaponName, self.Owner, self,
|
||||
Game.world.Add(new Missile(weapon, self.Owner, self,
|
||||
firePos, thisTarget, srcAltitude, fireFacing));
|
||||
}
|
||||
else
|
||||
Game.world.Add(new Bullet(weaponName, self.Owner, self,
|
||||
Game.world.Add(new Bullet(weapon, self.Owner, self,
|
||||
firePos, thisTarget.CenterLocation.ToInt2(), srcAltitude, destAltitude));
|
||||
|
||||
if (!string.IsNullOrEmpty(weapon.Report))
|
||||
@@ -161,10 +178,13 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
if (mi.Button == MouseButton.Left || underCursor == null) return null;
|
||||
if (self == underCursor) return null;
|
||||
var isHeal = Rules.WeaponInfo[self.Info.Primary].Damage < 0;
|
||||
|
||||
var isHeal = self.GetPrimaryWeapon().Damage < 0;
|
||||
if (((underCursor.Owner == self.Owner) ^ isHeal)
|
||||
&& !mi.Modifiers.HasModifier( Modifiers.Ctrl )) return null;
|
||||
|
||||
if (!Combat.HasAnyValidWeapons(self, underCursor)) return null;
|
||||
|
||||
return new Order(isHeal ? "Heal" : "Attack", self, underCursor, int2.Zero, null);
|
||||
}
|
||||
|
||||
@@ -186,10 +206,10 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
|
||||
/* todo: choose the appropriate weapon, when only one works against this target */
|
||||
var weapon = order.Subject.Info.Primary ?? order.Subject.Info.Secondary;
|
||||
var weapon = self.GetPrimaryWeapon() ?? self.GetSecondaryWeapon();
|
||||
|
||||
self.QueueActivity(new Activities.Attack(order.TargetActor,
|
||||
Math.Max(0, (int)Rules.WeaponInfo[weapon].Range - RangeTolerance)));
|
||||
Math.Max(0, (int)weapon.Range - RangeTolerance)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AttackHeliInfo : AttackBaseInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new AttackHeli(self); }
|
||||
}
|
||||
|
||||
class AttackHeli : AttackFrontal
|
||||
{
|
||||
public AttackHeli(Actor self) : base(self, 20) { }
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AttackPlaneInfo : AttackBaseInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new AttackPlane(self); }
|
||||
}
|
||||
|
||||
class AttackPlane : AttackFrontal
|
||||
{
|
||||
public AttackPlane(Actor self) : base(self, 20) { }
|
||||
|
||||
@@ -3,9 +3,14 @@ using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AttackTurretedInfo : AttackBaseInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new AttackTurreted( self ); }
|
||||
}
|
||||
|
||||
class AttackTurreted : AttackBase, INotifyBuildComplete
|
||||
{
|
||||
public AttackTurreted( Actor self ) : base(self) { self.traits.Get<Turreted>(); }
|
||||
public AttackTurreted(Actor self) : base(self) { }
|
||||
|
||||
public override void Tick(Actor self)
|
||||
{
|
||||
@@ -31,11 +36,11 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
|
||||
/* todo: choose the appropriate weapon, when only one works against this target */
|
||||
var weapon = order.Subject.Info.Primary ?? order.Subject.Info.Secondary;
|
||||
var weapon = order.Subject.GetPrimaryWeapon() ?? order.Subject.GetSecondaryWeapon();
|
||||
|
||||
if (self.traits.Contains<Mobile>())
|
||||
self.QueueActivity( new Traits.Activities.Follow( order.TargetActor,
|
||||
Math.Max( 0, (int)Rules.WeaponInfo[ weapon ].Range - RangeTolerance ) ) );
|
||||
Math.Max( 0, (int)weapon.Range - RangeTolerance ) ) );
|
||||
|
||||
target = order.TargetActor;
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AutoHealInfo : StatelessTraitInfo<AutoHeal> { }
|
||||
|
||||
class AutoHeal : ITick
|
||||
{
|
||||
public AutoHeal(Actor self) { }
|
||||
|
||||
void AttackTarget(Actor self, Actor target)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
if (target != null)
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
|
||||
else
|
||||
@@ -17,23 +17,16 @@ namespace OpenRa.Game.Traits
|
||||
self.CancelActivity();
|
||||
}
|
||||
|
||||
float GetMaximumRange(Actor self)
|
||||
{
|
||||
return new[] { self.Info.Primary, self.Info.Secondary }
|
||||
.Where(w => w != null)
|
||||
.Max(w => Rules.WeaponInfo[w].Range);
|
||||
}
|
||||
|
||||
bool NeedsNewTarget(Actor self)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var range = GetMaximumRange(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.Strength)
|
||||
if (attack.target.Health == attack.target.Info.Traits.Get<OwnedActorInfo>().HP)
|
||||
return true; // fully healed
|
||||
|
||||
return false;
|
||||
@@ -41,8 +34,8 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var range = GetMaximumRange(self);
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
var range = Util.GetMaximumRange(self);
|
||||
|
||||
if (NeedsNewTarget(self))
|
||||
AttackTarget(self, ChooseTarget(self, range));
|
||||
@@ -55,7 +48,7 @@ namespace OpenRa.Game.Traits
|
||||
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.Strength)
|
||||
.Where(a => a.Health < a.Info.Traits.Get<OwnedActorInfo>().HP)
|
||||
.OrderBy(a => (a.Location - self.Location).LengthSquared)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
@@ -2,30 +2,23 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AutoTargetInfo : StatelessTraitInfo<AutoTarget> { }
|
||||
|
||||
class AutoTarget : ITick, INotifyDamage
|
||||
{
|
||||
public AutoTarget(Actor self) {}
|
||||
|
||||
void AttackTarget(Actor self, Actor target)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
if (target != null)
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
|
||||
}
|
||||
|
||||
float GetMaximumRange(Actor self)
|
||||
{
|
||||
return new[] { self.Info.Primary, self.Info.Secondary }
|
||||
.Where(w => w != null)
|
||||
.Max(w => Rules.WeaponInfo[w].Range);
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!self.IsIdle) return;
|
||||
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var range = GetMaximumRange(self);
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
var range = Util.GetMaximumRange(self);
|
||||
|
||||
if (attack.target == null ||
|
||||
(attack.target.Location - self.Location).LengthSquared > range * range + 2)
|
||||
@@ -55,7 +48,7 @@ namespace OpenRa.Game.Traits
|
||||
if (e.Damage < 0)
|
||||
return; // don't retaliate against healers
|
||||
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
if (attack.target != null) return;
|
||||
|
||||
AttackTarget(self, e.Attacker);
|
||||
|
||||
@@ -3,10 +3,10 @@ using System.Linq;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class BelowUnitsInfo : StatelessTraitInfo<BelowUnits> { }
|
||||
|
||||
class BelowUnits : IRenderModifier
|
||||
{
|
||||
public BelowUnits(Actor self) { }
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
return r.Select(a => a.WithZOffset(-1));
|
||||
|
||||
23
OpenRa.Game/Traits/Buildable.cs
Executable file
23
OpenRa.Game/Traits/Buildable.cs
Executable file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class BuildableInfo : StatelessTraitInfo<Buildable>
|
||||
{
|
||||
public readonly int TechLevel = -1;
|
||||
public readonly string Tab = null;
|
||||
public readonly string[] Prerequisites = { };
|
||||
public readonly string[] BuiltAt = { };
|
||||
public readonly Race[] Owner = { };
|
||||
public readonly int Cost = 0;
|
||||
public readonly string Description = "";
|
||||
public readonly string LongDesc = "";
|
||||
public readonly string Icon = null;
|
||||
public readonly string[] AlternateName = { };
|
||||
}
|
||||
|
||||
class Buildable { }
|
||||
}
|
||||
@@ -9,35 +9,63 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class OwnedActorInfo
|
||||
{
|
||||
public readonly int HP = 0;
|
||||
public readonly ArmorType Armor = ArmorType.none;
|
||||
public readonly bool Crewed = false; // replace with trait?
|
||||
public readonly int Sight = 0;
|
||||
public readonly bool WaterBound = false;
|
||||
}
|
||||
|
||||
class BuildingInfo : OwnedActorInfo, ITraitInfo
|
||||
{
|
||||
public readonly int Power = 0;
|
||||
public readonly bool RequiresPower = false;
|
||||
public readonly bool BaseNormal = true;
|
||||
public readonly int Adjacent = 1;
|
||||
public readonly bool Bib = false;
|
||||
public readonly bool Capturable = false;
|
||||
public readonly bool Repairable = true;
|
||||
public readonly string Footprint = "x";
|
||||
public readonly string[] Produces = { }; // does this go somewhere else?
|
||||
public readonly int2 Dimensions = new int2(1, 1);
|
||||
public readonly bool Unsellable = false;
|
||||
|
||||
public object Create(Actor self) { return new Building(self); }
|
||||
}
|
||||
|
||||
class Building : INotifyDamage, IResolveOrder, ITick
|
||||
{
|
||||
readonly Actor self;
|
||||
public readonly BuildingInfo unitInfo;
|
||||
public readonly BuildingInfo Info;
|
||||
[Sync]
|
||||
bool isRepairing = false;
|
||||
[Sync]
|
||||
bool manuallyDisabled = false;
|
||||
public bool ManuallyDisabled { get { return manuallyDisabled; } }
|
||||
public bool Disabled { get { return (manuallyDisabled || (unitInfo.Powered && self.Owner.GetPowerState() != PowerState.Normal)); } }
|
||||
public bool Disabled { get { return (manuallyDisabled || (Info.RequiresPower && self.Owner.GetPowerState() != PowerState.Normal)); } }
|
||||
bool wasDisabled = false;
|
||||
|
||||
public Building(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
unitInfo = (BuildingInfo)self.Info;
|
||||
Info = self.Info.Traits.Get<BuildingInfo>();
|
||||
self.CenterLocation = Game.CellSize
|
||||
* ((float2)self.Location + .5f * (float2)unitInfo.Dimensions);
|
||||
* ((float2)self.Location + .5f * (float2)Info.Dimensions);
|
||||
}
|
||||
|
||||
public int GetPowerUsage()
|
||||
{
|
||||
if (manuallyDisabled)
|
||||
return 0;
|
||||
|
||||
if (unitInfo.Power > 0) /* todo: is this how real-ra scales it? */
|
||||
return (self.Health * unitInfo.Power) / unitInfo.Strength;
|
||||
|
||||
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
|
||||
|
||||
if (Info.Power > 0)
|
||||
return (self.Health * Info.Power) / maxHP;
|
||||
else
|
||||
return unitInfo.Power;
|
||||
return Info.Power;
|
||||
}
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
@@ -79,8 +107,9 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
if (remainingTicks == 0)
|
||||
{
|
||||
var costPerHp = (Rules.General.URepairPercent * self.Info.Cost) / self.Info.Strength;
|
||||
var hpToRepair = Math.Min(Rules.General.URepairStep, self.Info.Strength - self.Health);
|
||||
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
|
||||
var costPerHp = (Rules.General.URepairPercent * self.Info.Traits.Get<BuildableInfo>().Cost) / maxHP;
|
||||
var hpToRepair = Math.Min(Rules.General.URepairStep, maxHP - self.Health);
|
||||
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
|
||||
if (!self.Owner.TakeCash(cost))
|
||||
{
|
||||
@@ -90,7 +119,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
Game.world.AddFrameEndTask(w => w.Add(new RepairIndicator(self)));
|
||||
self.InflictDamage(self, -hpToRepair, Rules.WarheadInfo["Super"]);
|
||||
if (self.Health == self.Info.Strength)
|
||||
if (self.Health == maxHP)
|
||||
{
|
||||
isRepairing = false;
|
||||
return;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class C4DemolitionInfo : StatelessTraitInfo<C4Demolition> { }
|
||||
|
||||
class C4Demolition : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public C4Demolition(Actor self) { }
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
|
||||
@@ -7,6 +7,15 @@ using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class CargoInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Passengers = 0;
|
||||
public readonly UnitMovementType[] PassengerTypes = { };
|
||||
public readonly int UnloadFacing = 0;
|
||||
|
||||
public object Create(Actor self) { return new Cargo(self); }
|
||||
}
|
||||
|
||||
class Cargo : IPips, IIssueOrder, IResolveOrder
|
||||
{
|
||||
List<Actor> cargo = new List<Actor>();
|
||||
@@ -39,7 +48,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public bool IsFull(Actor self)
|
||||
{
|
||||
return cargo.Count == self.Info.Passengers;
|
||||
return cargo.Count == self.Info.Traits.Get<CargoInfo>().Passengers;
|
||||
}
|
||||
|
||||
public bool IsEmpty(Actor self)
|
||||
@@ -56,7 +65,8 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public IEnumerable<PipType> GetPips( Actor self )
|
||||
{
|
||||
for (var i = 0; i < self.Info.Passengers; i++)
|
||||
var numPips = self.Info.Traits.Get<CargoInfo>().Passengers;
|
||||
for (var i = 0; i < numPips; i++)
|
||||
if (i >= cargo.Count)
|
||||
yield return PipType.Transparent;
|
||||
else
|
||||
|
||||
@@ -4,6 +4,11 @@ using OpenRa.Game.Orders;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ChronoshiftDeployInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new ChronoshiftDeploy(self); }
|
||||
}
|
||||
|
||||
class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ISpeedModifier, ITick, IPips
|
||||
{
|
||||
// Recharge logic
|
||||
@@ -35,7 +40,7 @@ namespace OpenRa.Game.Traits
|
||||
return;
|
||||
}
|
||||
|
||||
var movement = self.traits.WithInterface<IMovement>().FirstOrDefault();
|
||||
var movement = self.traits.GetOrDefault<IMovement>();
|
||||
if (order.OrderString == "ChronoshiftSelf" && movement.CanEnterCell(order.TargetLocation))
|
||||
{
|
||||
// Cannot chronoshift into unexplored location
|
||||
|
||||
@@ -3,6 +3,9 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
// this is NOT bound through rules (it belongs on the world actor!)
|
||||
// so no *Info required
|
||||
|
||||
class ChronoshiftPaletteEffect : IPaletteModifier, ITick
|
||||
{
|
||||
const int chronoEffectLength = 20;
|
||||
|
||||
@@ -5,6 +5,11 @@ using System.Linq;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ChronoshiftableInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Chronoshiftable(self); }
|
||||
}
|
||||
|
||||
class Chronoshiftable : IResolveOrder, ISpeedModifier, ITick
|
||||
{
|
||||
// Return-to-sender logic
|
||||
@@ -40,7 +45,7 @@ namespace OpenRa.Game.Traits
|
||||
Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(self, power);
|
||||
}
|
||||
|
||||
var movement = self.traits.WithInterface<IMovement>().FirstOrDefault();
|
||||
var movement = self.traits.GetOrDefault<IMovement>();
|
||||
if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation))
|
||||
{
|
||||
// Cannot chronoshift into unexplored location
|
||||
|
||||
@@ -5,10 +5,10 @@ using System.Text;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ChronosphereInfo : StatelessTraitInfo<Chronosphere> { }
|
||||
|
||||
class Chronosphere : IResolveOrder
|
||||
{
|
||||
public Chronosphere(Actor self) { }
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "PlayAnimation")
|
||||
|
||||
@@ -4,6 +4,11 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class CloakInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Cloak(self); }
|
||||
}
|
||||
|
||||
class Cloak : IRenderModifier, INotifyAttack, ITick
|
||||
{
|
||||
[Sync]
|
||||
|
||||
@@ -3,6 +3,11 @@ using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ConstructionYardInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new ConstructionYard(self); }
|
||||
}
|
||||
|
||||
class ConstructionYard : IIssueOrder, IResolveOrder, IMovement
|
||||
{
|
||||
readonly Actor self;
|
||||
|
||||
@@ -6,19 +6,19 @@ using OpenRa.Game.Orders;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class DemoTruckInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new DemoTruck(self); }
|
||||
}
|
||||
|
||||
class DemoTruck : Chronoshiftable, IResolveOrder, INotifyDamage
|
||||
{
|
||||
readonly Actor self;
|
||||
public DemoTruck(Actor self)
|
||||
: base(self)
|
||||
{
|
||||
this.self = self;
|
||||
}
|
||||
public DemoTruck(Actor self) : base(self) {}
|
||||
|
||||
public new void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
// Override chronoshifting action to detonate vehicle
|
||||
var movement = self.traits.WithInterface<IMovement>().FirstOrDefault();
|
||||
var movement = self.traits.GetOrDefault<IMovement>();
|
||||
var chronosphere = Game.world.Actors.Where(a => a.Owner == order.Subject.Owner && a.traits.Contains<Chronosphere>()).FirstOrDefault();
|
||||
if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation))
|
||||
{
|
||||
@@ -44,7 +44,7 @@ namespace OpenRa.Game.Traits
|
||||
int2 detonateLocation = self.CenterLocation.ToInt2();
|
||||
|
||||
Game.world.AddFrameEndTask(
|
||||
w => w.Add(new Bullet(self.Info.Primary, detonatedBy.Owner, detonatedBy,
|
||||
w => w.Add( new Bullet( self.Info.Traits.Get<AttackBaseInfo>().PrimaryWeapon, detonatedBy.Owner, detonatedBy,
|
||||
detonateLocation, detonateLocation, altitude, altitude)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class EngineerCaptureInfo : StatelessTraitInfo<EngineerCapture> { }
|
||||
|
||||
class EngineerCapture : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public const int EngineerDamage = 300; // todo: push into rules, as a weapon
|
||||
|
||||
public EngineerCapture(Actor self) { }
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ExplodesInfo : StatelessTraitInfo<Explodes> { }
|
||||
|
||||
class Explodes : INotifyDamage
|
||||
{
|
||||
public Explodes(Actor self) {}
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
{
|
||||
if (self.IsDead)
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class FakeInfo : StatelessTraitInfo<Fake> { }
|
||||
|
||||
class Fake : ITags
|
||||
{
|
||||
public Fake(Actor self){}
|
||||
|
||||
public IEnumerable<TagType> GetTags()
|
||||
{
|
||||
yield return TagType.Fake;
|
||||
}
|
||||
public IEnumerable<TagType> GetTags() { yield return TagType.Fake; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class GpsLaunchSite { public GpsLaunchSite(Actor self) { } }
|
||||
class GpsLaunchSiteInfo : StatelessTraitInfo<GpsLaunchSite> { }
|
||||
class GpsLaunchSite { }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class HarvesterInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Harvester(); }
|
||||
}
|
||||
|
||||
class Harvester : IIssueOrder, IResolveOrder, IPips
|
||||
{
|
||||
[Sync]
|
||||
@@ -13,8 +18,6 @@ namespace OpenRa.Game.Traits
|
||||
public bool IsFull { get { return oreCarried + gemsCarried == Rules.General.BailCount; } }
|
||||
public bool IsEmpty { get { return oreCarried == 0 && gemsCarried == 0; } }
|
||||
|
||||
public Harvester(Actor self) { }
|
||||
|
||||
public void AcceptResource(bool isGem)
|
||||
{
|
||||
if (isGem) gemsCarried++;
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
using OpenRa.Game.Traits.Activities;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.GameRules;
|
||||
using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class HelicopterInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Helicopter(self); }
|
||||
}
|
||||
|
||||
class Helicopter : IIssueOrder, IResolveOrder, IMovement
|
||||
{
|
||||
public IDisposable reservation;
|
||||
public Helicopter(Actor self) {}
|
||||
|
||||
// todo: push into data!
|
||||
static bool HeliCanEnter(Actor a)
|
||||
{
|
||||
if (a.Info == Rules.UnitInfo["HPAD"]) return true;
|
||||
if (a.Info == Rules.UnitInfo["FIX"]) return true;
|
||||
if (a.Info.Name == "hpad") return true;
|
||||
if (a.Info.Name == "fix") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -44,7 +49,7 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new HeliFly(Util.CenterOfCell(order.TargetLocation)));
|
||||
self.QueueActivity(new Turn(self.Info.InitialFacing));
|
||||
self.QueueActivity( new Turn( self.Info.Traits.GetOrDefault<UnitInfo>().InitialFacing ) );
|
||||
self.QueueActivity(new HeliLand(true));
|
||||
}
|
||||
|
||||
@@ -55,14 +60,15 @@ namespace OpenRa.Game.Traits
|
||||
if (res != null)
|
||||
reservation = res.Reserve(self);
|
||||
|
||||
var offset = (order.TargetActor.Info as BuildingInfo).SpawnOffset;
|
||||
var productionInfo = order.TargetActor.Info.Traits.Get<ProductionInfo>();
|
||||
var offset = productionInfo.SpawnOffset;
|
||||
var offsetVec = offset != null ? new float2(offset[0], offset[1]) : float2.Zero;
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new HeliFly(order.TargetActor.CenterLocation + offsetVec));
|
||||
self.QueueActivity(new Turn(self.Info.InitialFacing));
|
||||
self.QueueActivity( new Turn( self.Info.Traits.GetOrDefault<UnitInfo>().InitialFacing ) );
|
||||
self.QueueActivity(new HeliLand(false));
|
||||
self.QueueActivity(order.TargetActor.Info == Rules.UnitInfo["HPAD"]
|
||||
self.QueueActivity(order.TargetActor.Info.Name == "hpad"
|
||||
? (IActivity)new Rearm() : new Repair());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class InvisibleToOthersInfo : StatelessTraitInfo<InvisibleToOthers> { }
|
||||
|
||||
class InvisibleToOthers : IRenderModifier
|
||||
{
|
||||
public InvisibleToOthers(Actor self) { }
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
return Game.LocalPlayer == self.Owner
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class IronCurtainInfo : StatelessTraitInfo<IronCurtain> { }
|
||||
|
||||
class IronCurtain : IResolveOrder
|
||||
{
|
||||
public IronCurtain(Actor self) {}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "PlayAnimation")
|
||||
|
||||
@@ -3,13 +3,16 @@ using OpenRa.Game.Effects;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class IronCurtainableInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new IronCurtainable(); }
|
||||
}
|
||||
|
||||
class IronCurtainable : IResolveOrder, IDamageModifier, ITick
|
||||
{
|
||||
[Sync]
|
||||
int RemainingTicks = 0;
|
||||
|
||||
public IronCurtainable(Actor self) { }
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (RemainingTicks > 0)
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class LimitedAmmoInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Ammo = 0;
|
||||
|
||||
public object Create(Actor self) { return new LimitedAmmo(self); }
|
||||
}
|
||||
|
||||
class LimitedAmmo : INotifyAttack, IPips
|
||||
{
|
||||
[Sync]
|
||||
@@ -10,14 +17,14 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public LimitedAmmo(Actor self)
|
||||
{
|
||||
ammo = self.Info.Ammo;
|
||||
ammo = self.Info.Traits.Get<LimitedAmmoInfo>().Ammo;
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public bool HasAmmo() { return ammo > 0; }
|
||||
public bool GiveAmmo()
|
||||
{
|
||||
if (ammo >= self.Info.Ammo) return false;
|
||||
if (ammo >= self.Info.Traits.Get<LimitedAmmoInfo>().Ammo) return false;
|
||||
++ammo;
|
||||
return true;
|
||||
}
|
||||
@@ -26,7 +33,8 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public IEnumerable<PipType> GetPips(Actor self)
|
||||
{
|
||||
return Graphics.Util.MakeArray(self.Info.Ammo,
|
||||
var maxAmmo = self.Info.Traits.Get<LimitedAmmoInfo>().Ammo;
|
||||
return Graphics.Util.MakeArray(maxAmmo,
|
||||
i => ammo > i ? PipType.Green : PipType.Transparent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class McvDeployInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new McvDeploy(self); }
|
||||
}
|
||||
|
||||
class McvDeploy : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public McvDeploy(Actor self) { }
|
||||
@@ -19,8 +24,8 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
if( order.OrderString == "DeployMcv" )
|
||||
{
|
||||
var factBuildingInfo = (BuildingInfo)Rules.UnitInfo[ "fact" ];
|
||||
if( Game.CanPlaceBuilding( factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) )
|
||||
var factBuildingInfo = Rules.NewUnitInfo[ "fact" ].Traits.Get<BuildingInfo>();
|
||||
if( Game.CanPlaceBuilding( "fact", factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) )
|
||||
{
|
||||
self.CancelActivity();
|
||||
self.QueueActivity( new Turn( 96 ) );
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class MineImmune
|
||||
{
|
||||
public MineImmune(Actor self) { }
|
||||
}
|
||||
class MineImmuneInfo : StatelessTraitInfo<MineImmune> { }
|
||||
class MineImmune { }
|
||||
}
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class MinelayerInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Mine = "minv";
|
||||
|
||||
public object Create( Actor self )
|
||||
{
|
||||
return new Minelayer();
|
||||
}
|
||||
}
|
||||
|
||||
class Minelayer : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public Minelayer(Actor self) { }
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
var limitedAmmo = self.traits.GetOrDefault<LimitedAmmo>();
|
||||
if (limitedAmmo != null && !limitedAmmo.HasAmmo())
|
||||
return null;
|
||||
|
||||
|
||||
// Ensure that the cell is empty except for the minelayer
|
||||
if (Game.UnitInfluence.GetUnitsAt( xy ).Any(a => a != self))
|
||||
if (Game.UnitInfluence.GetUnitsAt(xy).Any(a => a != self))
|
||||
return null;
|
||||
|
||||
if (mi.Button == MouseButton.Right && underCursor == self)
|
||||
@@ -36,7 +41,7 @@ namespace OpenRa.Game.Traits
|
||||
// todo: delay a bit? (req making deploy-mine an activity)
|
||||
|
||||
Game.world.AddFrameEndTask(
|
||||
w => w.Add(new Actor(Rules.UnitInfo[self.Info.Primary], self.Location, self.Owner)));
|
||||
w => w.Add(new Actor(self.Info.Traits.Get<MinelayerInfo>().Mine, self.Location, self.Owner)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@ using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class MobileInfo : ITraitInfo
|
||||
{
|
||||
public readonly UnitMovementType MovementType = UnitMovementType.Wheel;
|
||||
|
||||
public object Create(Actor self) { return new Mobile(self); }
|
||||
}
|
||||
|
||||
class Mobile : IIssueOrder, IResolveOrder, IOccupySpace, IMovement
|
||||
{
|
||||
readonly Actor self;
|
||||
@@ -78,19 +85,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public UnitMovementType GetMovementType()
|
||||
{
|
||||
switch (Rules.UnitCategory[self.Info.Name])
|
||||
{
|
||||
case "Infantry":
|
||||
return UnitMovementType.Foot;
|
||||
case "Vehicle":
|
||||
return (self.Info as VehicleInfo).Tracked ? UnitMovementType.Track : UnitMovementType.Wheel;
|
||||
case "Ship":
|
||||
return UnitMovementType.Float;
|
||||
case "Plane":
|
||||
return UnitMovementType.Fly;
|
||||
default:
|
||||
throw new InvalidOperationException("GetMovementType on unit that shouldn't be able to move.");
|
||||
}
|
||||
return self.Info.Traits.Get<MobileInfo>().MovementType;
|
||||
}
|
||||
|
||||
public bool CanEnterCell(int2 a)
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class PassengerInfo : StatelessTraitInfo<Passenger> {}
|
||||
|
||||
class Passenger : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public Passenger(Actor self) { }
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right)
|
||||
@@ -22,8 +19,8 @@ namespace OpenRa.Game.Traits
|
||||
if (cargo == null || cargo.IsFull(underCursor))
|
||||
return null;
|
||||
|
||||
var umt = self.traits.WithInterface<IMovement>().First().GetMovementType();
|
||||
if (!underCursor.Info.PassengerTypes.Contains(umt))
|
||||
var umt = self.traits.Get<IMovement>().GetMovementType();
|
||||
if (!underCursor.Info.Traits.Get<CargoInfo>().PassengerTypes.Contains(umt))
|
||||
return null;
|
||||
|
||||
return new Order("EnterTransport", self, underCursor, int2.Zero, null);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class PlaneInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Plane(self); }
|
||||
}
|
||||
|
||||
class Plane : IIssueOrder, IResolveOrder, IMovement
|
||||
{
|
||||
public IDisposable reservation;
|
||||
@@ -15,8 +17,8 @@ namespace OpenRa.Game.Traits
|
||||
// todo: push into data!
|
||||
static bool PlaneCanEnter(Actor a)
|
||||
{
|
||||
if (a.Info == Rules.UnitInfo["AFLD"]) return true;
|
||||
if (a.Info == Rules.UnitInfo["FIX"]) return true;
|
||||
if (a.Info.Name == "afld") return true;
|
||||
if (a.Info.Name == "fix") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new ReturnToBase(self, order.TargetActor));
|
||||
self.QueueActivity(order.TargetActor.Info == Rules.UnitInfo["AFLD"]
|
||||
self.QueueActivity(order.TargetActor.Info.Name == "afld"
|
||||
? (IActivity)new Rearm() : new Repair());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
using OpenRa.Game.GameRules;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ProductionInfo : ITraitInfo
|
||||
{
|
||||
public readonly int[] SpawnOffset = null;
|
||||
public readonly string[] Produces = { };
|
||||
|
||||
public object Create(Actor self) { return new Production(self); }
|
||||
}
|
||||
|
||||
class Production : IIssueOrder, IResolveOrder, IProducer, ITags
|
||||
{
|
||||
bool isPrimary = false;
|
||||
@@ -11,23 +19,23 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public Production( Actor self ) { }
|
||||
|
||||
public virtual int2? CreationLocation( Actor self, UnitInfo producee )
|
||||
public virtual int2? CreationLocation( Actor self, NewUnitInfo producee )
|
||||
{
|
||||
return ( 1 / 24f * self.CenterLocation ).ToInt2();
|
||||
}
|
||||
|
||||
public virtual int CreationFacing( Actor self, Actor newUnit )
|
||||
{
|
||||
return newUnit.Info.InitialFacing;
|
||||
return newUnit.Info.Traits.GetOrDefault<UnitInfo>().InitialFacing;
|
||||
}
|
||||
|
||||
public bool Produce( Actor self, UnitInfo producee )
|
||||
public bool Produce( Actor self, NewUnitInfo producee )
|
||||
{
|
||||
var location = CreationLocation( self, producee );
|
||||
if( location == null || Game.UnitInfluence.GetUnitsAt( location.Value ).Any() )
|
||||
return false;
|
||||
|
||||
var newUnit = new Actor( producee, location.Value, self.Owner );
|
||||
var newUnit = new Actor( producee.Name, location.Value, self.Owner );
|
||||
newUnit.traits.Get<Unit>().Facing = CreationFacing( self, newUnit ); ;
|
||||
|
||||
var rp = self.traits.GetOrDefault<RallyPoint>();
|
||||
@@ -38,10 +46,10 @@ namespace OpenRa.Game.Traits
|
||||
newUnit.QueueActivity( new Activities.Move( rp.rallyPoint, 1 ) );
|
||||
}
|
||||
|
||||
var bi = self.Info as BuildingInfo;
|
||||
if (bi != null && bi.SpawnOffset != null)
|
||||
var pi = self.Info.Traits.Get<ProductionInfo>();
|
||||
if (pi != null && pi.SpawnOffset != null)
|
||||
newUnit.CenterLocation = self.CenterLocation
|
||||
+ new float2(bi.SpawnOffset[0], bi.SpawnOffset[1]);
|
||||
+ new float2(pi.SpawnOffset[0], pi.SpawnOffset[1]);
|
||||
|
||||
Game.world.Add( newUnit );
|
||||
|
||||
@@ -78,12 +86,12 @@ namespace OpenRa.Game.Traits
|
||||
}
|
||||
|
||||
// Cancel existing primaries
|
||||
foreach (var p in (self.Info as BuildingInfo).Produces)
|
||||
foreach (var p in self.Info.Traits.Get<ProductionInfo>().Produces)
|
||||
{
|
||||
foreach (var b in Game.world.Actors.Where(x => x.traits.Contains<Production>()
|
||||
&& x.Owner == self.Owner
|
||||
&& x.traits.Get<Production>().IsPrimary == true
|
||||
&& (x.Info as BuildingInfo).Produces.Contains(p)))
|
||||
&& (x.Info.Traits.Get<ProductionInfo>().Produces.Contains(p))))
|
||||
{
|
||||
b.traits.Get<Production>().SetPrimaryProducer(b, false);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ using IjwFramework.Collections;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ProductionQueueInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new ProductionQueue(self); }
|
||||
}
|
||||
|
||||
class ProductionQueue : IResolveOrder, ITick
|
||||
{
|
||||
Actor self;
|
||||
@@ -29,7 +34,7 @@ namespace OpenRa.Game.Traits
|
||||
case "StartProduction":
|
||||
{
|
||||
string group = Rules.UnitCategory[ order.TargetString ];
|
||||
var ui = Rules.UnitInfo[ order.TargetString ];
|
||||
var ui = Rules.NewUnitInfo[ order.TargetString ].Traits.Get<BuildableInfo>();
|
||||
var time = ui.Cost
|
||||
* Rules.General.BuildSpeed /* todo: country-specific build speed bonus */
|
||||
* ( 25 * 60 ) /* frames per min */ /* todo: build acceleration, if we do that */
|
||||
@@ -121,7 +126,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public void BuildUnit( string name )
|
||||
{
|
||||
var newUnitType = Rules.UnitInfo[ name ];
|
||||
var newUnitType = Rules.NewUnitInfo[ name ];
|
||||
var producerTypes = Rules.TechTree.UnitBuiltAt( newUnitType );
|
||||
Actor producer = null;
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ProductionSurroundInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new ProductionSurround(self); }
|
||||
}
|
||||
|
||||
class ProductionSurround : Production
|
||||
{
|
||||
public ProductionSurround(Actor self) : base(self) { }
|
||||
@@ -24,9 +26,9 @@ namespace OpenRa.Game.Traits
|
||||
return null;
|
||||
}
|
||||
|
||||
public override int2? CreationLocation(Actor self, UnitInfo producee)
|
||||
public override int2? CreationLocation(Actor self, NewUnitInfo producee)
|
||||
{
|
||||
return FindAdjacentTile(self, producee.WaterBound ?
|
||||
return FindAdjacentTile(self, producee.Traits.Get<OwnedActorInfo>().WaterBound ?
|
||||
UnitMovementType.Float : UnitMovementType.Wheel); /* hackety hack */
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ProvidesRadarInfo : StatelessTraitInfo<ProvidesRadar> {}
|
||||
|
||||
class ProvidesRadar
|
||||
{
|
||||
Actor self;
|
||||
public ProvidesRadar(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public bool IsActive()
|
||||
public bool IsActive(Actor self)
|
||||
{
|
||||
// TODO: Check for nearby MRJ
|
||||
|
||||
|
||||
@@ -4,6 +4,13 @@ using OpenRa.Game.Orders;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RallyPointInfo : ITraitInfo
|
||||
{
|
||||
public readonly int[] RallyPoint = { 1, 3 };
|
||||
|
||||
public object Create(Actor self) { return new RallyPoint(self); }
|
||||
}
|
||||
|
||||
class RallyPoint : IRender, IIssueOrder, IResolveOrder, ITick
|
||||
{
|
||||
[Sync]
|
||||
@@ -12,8 +19,8 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public RallyPoint(Actor self)
|
||||
{
|
||||
var bi = self.traits.Get<Building>().unitInfo;
|
||||
rallyPoint = self.Location + new int2(bi.RallyPoint[0], bi.RallyPoint[1]);
|
||||
var info = self.Info.Traits.Get<RallyPointInfo>();
|
||||
rallyPoint = self.Location + new int2(info.RallyPoint[0], info.RallyPoint[1]);
|
||||
anim = new Animation("flagfly");
|
||||
anim.PlayRepeating("idle");
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRa.Game.Graphics;
|
||||
using OpenRa.Game.Effects;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderBuildingInfo : RenderSimpleInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderBuilding(self); }
|
||||
}
|
||||
|
||||
class RenderBuilding : RenderSimple, INotifyDamage, INotifySold
|
||||
{
|
||||
const int SmallBibStart = 1;
|
||||
@@ -30,7 +33,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
void DoBib(Actor self, bool isRemove)
|
||||
{
|
||||
var buildingInfo = self.traits.Get<Building>().unitInfo;
|
||||
var buildingInfo = self.Info.Traits.Get<BuildingInfo>();
|
||||
if (buildingInfo.Bib)
|
||||
{
|
||||
var size = buildingInfo.Dimensions.X;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderBuildingChargeInfo : RenderBuildingInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderBuildingCharge(self); }
|
||||
}
|
||||
|
||||
/* used for tesla */
|
||||
class RenderBuildingCharge : RenderBuilding, INotifyAttack
|
||||
{
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderBuildingOreInfo : RenderBuildingInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderBuildingOre(self); }
|
||||
}
|
||||
|
||||
class RenderBuildingOre : RenderBuilding, INotifyBuildComplete
|
||||
{
|
||||
public RenderBuildingOre(Actor self)
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderBuildingTurretedInfo : RenderBuildingInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderBuildingTurreted(self); }
|
||||
}
|
||||
|
||||
class RenderBuildingTurreted : RenderBuilding, INotifyBuildComplete
|
||||
{
|
||||
public RenderBuildingTurreted(Actor self)
|
||||
|
||||
@@ -4,6 +4,11 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderWarFactoryInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new RenderWarFactory(self); }
|
||||
}
|
||||
|
||||
class RenderWarFactory : IRender, INotifyBuildComplete, INotifyDamage, ITick, INotifyProduction
|
||||
{
|
||||
public Animation roof;
|
||||
@@ -21,7 +26,7 @@ namespace OpenRa.Game.Traits
|
||||
public RenderWarFactory(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
roof = new Animation(self.Info.Image ?? self.Info.Name);
|
||||
roof = new Animation(self.traits.Get<RenderSimple>().GetImage(self));
|
||||
}
|
||||
|
||||
public void BuildingComplete( Actor self )
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRa.Game.Graphics;
|
||||
using OpenRa.Game.GameRules;
|
||||
using OpenRa.Game.Effects;
|
||||
using OpenRa.Game.Effects;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderInfantryInfo : RenderSimpleInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderInfantry(self); }
|
||||
}
|
||||
|
||||
class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage
|
||||
{
|
||||
public RenderInfantry(Actor self)
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using IjwFramework.Collections;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
abstract class RenderSimpleInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Image = null;
|
||||
|
||||
public abstract object Create(Actor self);
|
||||
}
|
||||
|
||||
abstract class RenderSimple : IRender, ITick
|
||||
{
|
||||
public Dictionary<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>();
|
||||
public Animation anim { get { return anims[ "" ].Animation; } }
|
||||
|
||||
public string GetImage(Actor self)
|
||||
{
|
||||
return self.Info.Traits.Get<RenderSimpleInfo>().Image ?? self.Info.Name;
|
||||
}
|
||||
|
||||
public RenderSimple(Actor self)
|
||||
{
|
||||
anims.Add( "", new Animation( self.Info.Image ?? self.Info.Name ) );
|
||||
anims.Add( "", new Animation( GetImage(self) ) );
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Renderable> Render( Actor self )
|
||||
|
||||
@@ -5,6 +5,11 @@ using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderUnitInfo : RenderSimpleInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderUnit(self); }
|
||||
}
|
||||
|
||||
class RenderUnit : RenderSimple, INotifyDamage
|
||||
{
|
||||
public RenderUnit(Actor self)
|
||||
|
||||
@@ -5,22 +5,26 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderUnitMuzzleFlashInfo : RenderUnitInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderUnitMuzzleFlash(self); }
|
||||
}
|
||||
|
||||
class RenderUnitMuzzleFlash : RenderUnit
|
||||
{
|
||||
public RenderUnitMuzzleFlash(Actor self)
|
||||
: base(self)
|
||||
{
|
||||
if (!self.Info.MuzzleFlash) throw new InvalidOperationException("wtf??");
|
||||
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var attack = self.traits.Get<AttackBase>();
|
||||
var attackInfo = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
|
||||
var muzzleFlash = new Animation(self.Info.Name);
|
||||
var muzzleFlash = new Animation(GetImage(self));
|
||||
muzzleFlash.PlayFetchIndex("muzzle",
|
||||
() => (Util.QuantizeFacing(unit.Facing, 8)) * 6 + (int)(attack.primaryRecoil * 5.9f));
|
||||
anims.Add( "muzzle", new AnimationWithOffset(
|
||||
muzzleFlash,
|
||||
() => self.Info.PrimaryOffset.AbsOffset(),
|
||||
() => attackInfo.PrimaryOffset.AbsOffset(),
|
||||
() => attack.primaryRecoil <= 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderUnitReloadInfo : RenderUnitInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderUnitReload(self); }
|
||||
}
|
||||
|
||||
class RenderUnitReload : RenderUnit
|
||||
{
|
||||
public RenderUnitReload(Actor self)
|
||||
@@ -11,7 +16,7 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
var isAttacking = self.GetCurrentActivity() is Activities.Attack;
|
||||
|
||||
var attack = self.traits.WithInterface<AttackBase>().FirstOrDefault();
|
||||
var attack = self.traits.GetOrDefault<AttackBase>();
|
||||
|
||||
if (attack != null)
|
||||
anim.ReplaceAnim((attack.IsReloading() ? "empty-" : "")
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderUnitRotorInfo : RenderUnitInfo
|
||||
{
|
||||
public readonly int[] PrimaryOffset = { 0, 0 };
|
||||
public readonly int[] SecondaryOffset = null;
|
||||
|
||||
public override object Create(Actor self) { return new RenderUnitRotor(self); }
|
||||
}
|
||||
|
||||
class RenderUnitRotor : RenderUnit
|
||||
{
|
||||
public Animation rotorAnim, secondRotorAnim;
|
||||
@@ -10,21 +18,22 @@ namespace OpenRa.Game.Traits
|
||||
: base(self)
|
||||
{
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var info = self.Info.Traits.Get<RenderUnitRotorInfo>();
|
||||
|
||||
rotorAnim = new Animation(self.Info.Name);
|
||||
rotorAnim = new Animation(GetImage(self));
|
||||
rotorAnim.PlayRepeating("rotor");
|
||||
anims.Add( "rotor_1", new AnimationWithOffset(
|
||||
rotorAnim,
|
||||
() => Util.GetTurretPosition( self, unit, self.Info.RotorOffset, 0 ),
|
||||
() => Util.GetTurretPosition( self, unit, info.PrimaryOffset, 0 ),
|
||||
null ) );
|
||||
|
||||
if (self.Info.RotorOffset2 == null) return;
|
||||
if (info.SecondaryOffset == null) return;
|
||||
|
||||
secondRotorAnim = new Animation( self.Info.Name );
|
||||
secondRotorAnim = new Animation(GetImage(self));
|
||||
secondRotorAnim.PlayRepeating( "rotor2" );
|
||||
anims.Add( "rotor_2", new AnimationWithOffset(
|
||||
secondRotorAnim,
|
||||
() => Util.GetTurretPosition(self, unit, self.Info.RotorOffset2, 0),
|
||||
() => Util.GetTurretPosition(self, unit, info.SecondaryOffset, 0),
|
||||
null ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderUnitSpinnerInfo : RenderUnitInfo
|
||||
{
|
||||
public readonly int[] Offset = { 0, 0 };
|
||||
public override object Create(Actor self) { return new RenderUnitSpinner(self); }
|
||||
}
|
||||
|
||||
class RenderUnitSpinner : RenderUnit
|
||||
{
|
||||
public Animation spinnerAnim;
|
||||
|
||||
public RenderUnitSpinner( Actor self )
|
||||
: base(self)
|
||||
{
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var info = self.Info.Traits.Get<RenderUnitSpinnerInfo>();
|
||||
|
||||
spinnerAnim = new Animation( self.Info.Name );
|
||||
var spinnerAnim = new Animation( GetImage(self) );
|
||||
spinnerAnim.PlayRepeating( "spinner" );
|
||||
anims.Add( "spinner", new AnimationWithOffset(
|
||||
spinnerAnim,
|
||||
() => Util.GetTurretPosition( self, unit, self.Info.PrimaryOffset, 0 ),
|
||||
() => Util.GetTurretPosition( self, unit, info.Offset, 0 ),
|
||||
null ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,41 +4,45 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RenderUnitTurretedInfo : RenderUnitInfo
|
||||
{
|
||||
public override object Create(Actor self) { return new RenderUnitTurreted(self); }
|
||||
}
|
||||
|
||||
class RenderUnitTurreted : RenderUnit
|
||||
{
|
||||
public Animation muzzleFlash;
|
||||
|
||||
public RenderUnitTurreted(Actor self)
|
||||
: base(self)
|
||||
{
|
||||
var unit = self.traits.Get<Unit>();
|
||||
var turreted = self.traits.Get<Turreted>();
|
||||
var attack = self.traits.WithInterface<AttackBase>().FirstOrDefault();
|
||||
var attack = self.traits.GetOrDefault<AttackBase>();
|
||||
var attackInfo = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
|
||||
var turretAnim = new Animation(self.Info.Name);
|
||||
var turretAnim = new Animation(GetImage(self));
|
||||
turretAnim.PlayFacing( "turret", () => turreted.turretFacing );
|
||||
|
||||
if( self.Info.PrimaryOffset != null )
|
||||
if( attackInfo.PrimaryOffset != null )
|
||||
anims.Add("turret_1", new AnimationWithOffset(
|
||||
turretAnim,
|
||||
() => Util.GetTurretPosition(self, unit, self.Info.PrimaryOffset, attack.primaryRecoil),
|
||||
() => Util.GetTurretPosition(self, unit, attackInfo.PrimaryOffset, attack.primaryRecoil),
|
||||
null) { ZOffset = 1 });
|
||||
|
||||
if( self.Info.SecondaryOffset != null )
|
||||
if (attackInfo.SecondaryOffset != null)
|
||||
anims.Add("turret_2", new AnimationWithOffset(
|
||||
turretAnim,
|
||||
() => Util.GetTurretPosition(self, unit, self.Info.SecondaryOffset, attack.secondaryRecoil),
|
||||
() => Util.GetTurretPosition(self, unit, attackInfo.SecondaryOffset, attack.secondaryRecoil),
|
||||
null) { ZOffset = 1 });
|
||||
|
||||
if( self.Info.MuzzleFlash )
|
||||
if( attackInfo.MuzzleFlash )
|
||||
{
|
||||
muzzleFlash = new Animation( self.Info.Name );
|
||||
var muzzleFlash = new Animation( GetImage(self) );
|
||||
muzzleFlash.PlayFetchIndex( "muzzle",
|
||||
() => ( Util.QuantizeFacing( self.traits.Get<Turreted>().turretFacing, 8 ) ) * 6
|
||||
+ (int)( attack.primaryRecoil * 5.9f ) ); /* hack: recoil can be 1.0f, but don't overflow into next anim */
|
||||
anims.Add( "muzzle_flash", new AnimationWithOffset(
|
||||
muzzleFlash,
|
||||
() => Util.GetTurretPosition( self, unit, self.Info.PrimaryOffset, attack.primaryRecoil ),
|
||||
() => Util.GetTurretPosition(self, unit, attackInfo.PrimaryOffset, attack.primaryRecoil),
|
||||
() => attack.primaryRecoil <= 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ using OpenRa.Game.Traits.Activities;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class RepairableInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Repairable(self); }
|
||||
}
|
||||
|
||||
class Repairable : IIssueOrder, IResolveOrder
|
||||
{
|
||||
IDisposable reservation;
|
||||
@@ -16,7 +21,7 @@ namespace OpenRa.Game.Traits
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
if (underCursor == null) return null;
|
||||
|
||||
if (underCursor.Info == Rules.UnitInfo["FIX"]
|
||||
if (underCursor.Info.Name == "fix"
|
||||
&& underCursor.Owner == self.Owner
|
||||
&& !Reservable.IsReserved(underCursor))
|
||||
return new Order("Enter", self, underCursor, int2.Zero, null);
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ReservableInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Reservable(self); }
|
||||
}
|
||||
|
||||
class Reservable : ITick
|
||||
{
|
||||
public Reservable(Actor self) { }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class SeedsOreInfo : StatelessTraitInfo<SeedsOre> {}
|
||||
|
||||
class SeedsOre : ITick
|
||||
{
|
||||
public SeedsOre( Actor self ) {}
|
||||
|
||||
const double OreSeedProbability = .05; // todo: push this out into rules
|
||||
|
||||
public void Tick(Actor self)
|
||||
|
||||
16
OpenRa.Game/Traits/Selectable.cs
Executable file
16
OpenRa.Game/Traits/Selectable.cs
Executable file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class SelectableInfo : StatelessTraitInfo<Selectable>
|
||||
{
|
||||
public readonly int Priority = 10;
|
||||
public readonly int[] Bounds = null;
|
||||
public readonly string Voice = "GenericVoice";
|
||||
}
|
||||
|
||||
class Selectable {}
|
||||
}
|
||||
@@ -5,6 +5,11 @@ using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class SquishByTankInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new SquishByTank(self); }
|
||||
}
|
||||
|
||||
class SquishByTank : ICrushable
|
||||
{
|
||||
readonly Actor self;
|
||||
|
||||
@@ -3,21 +3,18 @@ using System;
|
||||
using OpenRa.Game.GameRules;
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class StoresOreInfo : StatelessTraitInfo<StoresOre>
|
||||
{
|
||||
public readonly int Pips = 0;
|
||||
public readonly int Capacity = 0;
|
||||
}
|
||||
|
||||
class StoresOre : IPips, IAcceptThief
|
||||
{
|
||||
public const int MaxStealAmount = 100; //todo: How is cash stolen determined?
|
||||
|
||||
readonly Actor self;
|
||||
|
||||
public StoresOre(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public void OnSteal(Actor self, Actor thief)
|
||||
{
|
||||
// Steal half the ore the building holds
|
||||
var toSteal = (self.Info as BuildingInfo).Storage/2;
|
||||
var toSteal = self.Info.Traits.Get<StoresOreInfo>().Capacity / 2;
|
||||
self.Owner.TakeCash(toSteal);
|
||||
thief.Owner.GiveCash(toSteal);
|
||||
|
||||
@@ -31,15 +28,12 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public IEnumerable<PipType> GetPips(Actor self)
|
||||
{
|
||||
for (int i = 0; i < self.Info.OrePips; i++)
|
||||
{
|
||||
if (Game.LocalPlayer.GetSiloFullness() > i * 1.0f / self.Info.OrePips)
|
||||
{
|
||||
yield return PipType.Yellow;
|
||||
continue;
|
||||
}
|
||||
yield return PipType.Transparent;
|
||||
}
|
||||
var numPips = self.Info.Traits.Get<StoresOreInfo>().Pips;
|
||||
|
||||
return Graphics.Util.MakeArray( numPips,
|
||||
i => (Game.LocalPlayer.GetSiloFullness() > i * 1.0f / numPips)
|
||||
? PipType.Yellow : PipType.Transparent );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class SubmarineInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new Submarine(self); }
|
||||
}
|
||||
|
||||
class Submarine : IRenderModifier, INotifyAttack, ITick, INotifyDamage
|
||||
{
|
||||
[Sync]
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class TakeCoverInfo : ITraitInfo
|
||||
{
|
||||
public object Create(Actor self) { return new TakeCover(self); }
|
||||
}
|
||||
|
||||
// infantry prone behavior
|
||||
class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier
|
||||
{
|
||||
|
||||
@@ -3,10 +3,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class ThiefInfo : StatelessTraitInfo<Thief> { }
|
||||
|
||||
class Thief : IIssueOrder, IResolveOrder
|
||||
{
|
||||
public Thief(Actor self) { }
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button != MouseButton.Right) return null;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using OpenRa.Game.GameRules;
|
||||
using OpenRa.Game.Graphics;
|
||||
using IjwFramework.Types;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
@@ -24,7 +25,7 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
interface IProducer
|
||||
{
|
||||
bool Produce( Actor self, UnitInfo producee );
|
||||
bool Produce( Actor self, NewUnitInfo producee );
|
||||
void SetPrimaryProducer(Actor self, bool isPrimary);
|
||||
}
|
||||
interface IOccupySpace { IEnumerable<int2> OccupiedCells(); }
|
||||
@@ -69,4 +70,14 @@ namespace OpenRa.Game.Traits
|
||||
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, newOffset); }
|
||||
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, ZOffset); }
|
||||
}
|
||||
|
||||
interface ITraitInfo { object Create(Actor self); }
|
||||
|
||||
class StatelessTraitInfo<T> : ITraitInfo
|
||||
where T : new()
|
||||
{
|
||||
static Lazy<T> Instance = Lazy.New(() => new T());
|
||||
public object Create(Actor self) { return Instance.Value; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class Tree : IRender
|
||||
{
|
||||
Sprite Image;
|
||||
|
||||
public Tree(Sprite treeImage)
|
||||
{
|
||||
Image = treeImage;
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> Render(Actor self)
|
||||
{
|
||||
yield return new Renderable(Image, Game.CellSize * (float2)self.Location, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class TurretedInfo : ITraitInfo
|
||||
{
|
||||
public readonly int ROT = 0;
|
||||
public readonly int InitialFacing = 128;
|
||||
|
||||
public object Create(Actor self) { return new Turreted(self); }
|
||||
}
|
||||
|
||||
class Turreted : ITick
|
||||
{
|
||||
[Sync]
|
||||
@@ -9,13 +18,13 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public Turreted(Actor self)
|
||||
{
|
||||
turretFacing = self.Info.InitialFacing;
|
||||
turretFacing = self.Info.Traits.Get<TurretedInfo>().InitialFacing;
|
||||
}
|
||||
|
||||
public void Tick( Actor self )
|
||||
{
|
||||
var df = desiredFacing ?? ( self.traits.Contains<Unit>() ? self.traits.Get<Unit>().Facing : turretFacing );
|
||||
Util.TickFacing( ref turretFacing, df, self.Info.ROT );
|
||||
Util.TickFacing(ref turretFacing, df, self.Info.Traits.Get<TurretedInfo>().ROT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
|
||||
using OpenRa.Game.GameRules;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class UnitInfo : OwnedActorInfo, ITraitInfo
|
||||
{
|
||||
public readonly int InitialFacing = 128;
|
||||
public readonly int ROT = 0;
|
||||
public readonly int Speed = 0;
|
||||
|
||||
public object Create( Actor self ) { return new Unit( self ); }
|
||||
}
|
||||
|
||||
class Unit : INotifyDamage
|
||||
{
|
||||
[Sync]
|
||||
|
||||
@@ -82,14 +82,14 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
static float2 GetRecoil(Actor self, float recoil)
|
||||
{
|
||||
if (self.Info.Recoil == 0) return float2.Zero;
|
||||
var rut = self.traits.WithInterface<RenderUnitTurreted>().FirstOrDefault();
|
||||
if (self.Info.Traits.Get<AttackBaseInfo>().Recoil == 0) return float2.Zero;
|
||||
var rut = self.traits.GetOrDefault<RenderUnitTurreted>();
|
||||
if (rut == null) return float2.Zero;
|
||||
|
||||
var facing = self.traits.Get<Turreted>().turretFacing;
|
||||
var quantizedFacing = QuantizeFacing(facing, rut.anim.CurrentSequence.Length) * (256 / rut.anim.CurrentSequence.Length);
|
||||
|
||||
return RotateVectorByFacing(new float2(0, recoil * self.Info.Recoil), quantizedFacing, .7f);
|
||||
return RotateVectorByFacing(new float2(0, recoil * self.Info.Traits.Get<AttackBaseInfo>().Recoil), quantizedFacing, .7f);
|
||||
}
|
||||
|
||||
public static float2 CenterOfCell(int2 loc)
|
||||
@@ -106,7 +106,7 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
if( unit == null ) return int2.Zero; /* things that don't have a rotating base don't need the turrets repositioned */
|
||||
|
||||
var ru = self.traits.WithInterface<RenderUnit>().FirstOrDefault();
|
||||
var ru = self.traits.GetOrDefault<RenderUnit>();
|
||||
var numDirs = (ru != null) ? ru.anim.CurrentSequence.Length : 8;
|
||||
var bodyFacing = unit.Facing;
|
||||
var quantizedFacing = QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs);
|
||||
@@ -127,14 +127,14 @@ namespace OpenRa.Game.Traits
|
||||
|
||||
public static float GetEffectiveSpeed(Actor self)
|
||||
{
|
||||
var mi = self.Info as MobileInfo;
|
||||
if (mi == null) return 0f;
|
||||
var unitInfo = self.Info.Traits.GetOrDefault<UnitInfo>();
|
||||
if( unitInfo == null ) return 0f;
|
||||
|
||||
var modifier = self.traits
|
||||
.WithInterface<ISpeedModifier>()
|
||||
.Select(t => t.GetSpeedModifier())
|
||||
.Product();
|
||||
return mi.Speed * modifier;
|
||||
return unitInfo.Speed * modifier;
|
||||
}
|
||||
|
||||
public static IActivity SequenceActivities(params IActivity[] acts)
|
||||
@@ -142,5 +142,12 @@ namespace OpenRa.Game.Traits
|
||||
return acts.Reverse().Aggregate(
|
||||
(next, a) => { a.NextActivity = next; return a; });
|
||||
}
|
||||
|
||||
public static float GetMaximumRange(Actor self)
|
||||
{
|
||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
return new[] { self.GetPrimaryWeapon(), self.GetSecondaryWeapon() }
|
||||
.Where(w => w != null).Max(w => w.Range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
// this is NOT bound through rules (it belongs on the world actor!)
|
||||
// so no *Info required
|
||||
|
||||
class WaterPaletteRotation : ITick, IPaletteModifier
|
||||
{
|
||||
public WaterPaletteRotation(Actor self) { }
|
||||
|
||||
@@ -6,10 +6,10 @@ using OpenRa.Game.Graphics;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class WithShadowInfo : StatelessTraitInfo<WithShadow> {}
|
||||
|
||||
class WithShadow : IRenderModifier
|
||||
{
|
||||
public WithShadow(Actor self) {}
|
||||
|
||||
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
|
||||
{
|
||||
var unit = self.traits.Get<Unit>();
|
||||
|
||||
Reference in New Issue
Block a user