Merge pull request #3063 from pchote/repairable-bridges
Repairable bridges, closes #2619
This commit is contained in:
@@ -54,9 +54,12 @@ namespace OpenRA.Orders
|
||||
.OrderByDescending(a => a.SelectionPriority())
|
||||
.FirstOrDefault();
|
||||
|
||||
if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())
|
||||
if (underCursor != null && underCursor.HasTrait<Selectable>())
|
||||
if (underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()))
|
||||
{
|
||||
var selectable = underCursor.TraitOrDefault<Selectable>();
|
||||
if (selectable != null && selectable.Info.Selectable)
|
||||
useSelect = true;
|
||||
}
|
||||
|
||||
var orders = world.Selection.Actors
|
||||
.Select(a => OrderForUnit(a, xy, mi, underCursor))
|
||||
|
||||
@@ -69,6 +69,35 @@ namespace OpenRA.Traits
|
||||
}
|
||||
}
|
||||
|
||||
public void Resurrect(Actor self, Actor repairer)
|
||||
{
|
||||
if (!IsDead)
|
||||
return;
|
||||
|
||||
hp = MaxHP;
|
||||
|
||||
var ai = new AttackInfo
|
||||
{
|
||||
Attacker = repairer,
|
||||
Damage = -MaxHP,
|
||||
DamageState = this.DamageState,
|
||||
PreviousDamageState = DamageState.Dead,
|
||||
Warhead = null,
|
||||
};
|
||||
|
||||
foreach (var nd in self.TraitsImplementing<INotifyDamage>()
|
||||
.Concat(self.Owner.PlayerActor.TraitsImplementing<INotifyDamage>()))
|
||||
nd.Damaged(self, ai);
|
||||
|
||||
foreach (var nd in self.TraitsImplementing<INotifyDamageStateChanged>())
|
||||
nd.DamageStateChanged(self, ai);
|
||||
|
||||
if (repairer != null && repairer.IsInWorld && !repairer.IsDead())
|
||||
foreach (var nd in repairer.TraitsImplementing<INotifyAppliedDamage>()
|
||||
.Concat(repairer.Owner.PlayerActor.TraitsImplementing<INotifyAppliedDamage>()))
|
||||
nd.AppliedDamage(repairer, self, ai);
|
||||
}
|
||||
|
||||
public void InflictDamage(Actor self, Actor attacker, int damage, WarheadInfo warhead, bool ignoreModifiers)
|
||||
{
|
||||
if (IsDead) return; /* overkill! don't count extra hits as more kills! */
|
||||
|
||||
@@ -16,21 +16,30 @@ namespace OpenRA.Traits
|
||||
{
|
||||
public class SelectableInfo : ITraitInfo
|
||||
{
|
||||
public readonly bool Selectable = true;
|
||||
public readonly int Priority = 10;
|
||||
public readonly int[] Bounds = null;
|
||||
[VoiceReference] public readonly string Voice = null;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Selectable(init.self); }
|
||||
public object Create(ActorInitializer init) { return new Selectable(init.self, this); }
|
||||
}
|
||||
|
||||
public class Selectable : IPostRenderSelection
|
||||
{
|
||||
public SelectableInfo Info;
|
||||
Actor self;
|
||||
|
||||
public Selectable(Actor self) { this.self = self; }
|
||||
public Selectable(Actor self, SelectableInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public void RenderAfterWorld(WorldRenderer wr)
|
||||
{
|
||||
if (!Info.Selectable)
|
||||
return;
|
||||
|
||||
var bounds = self.Bounds.Value;
|
||||
|
||||
var xy = new float2(bounds.Left, bounds.Top);
|
||||
@@ -44,6 +53,9 @@ namespace OpenRA.Traits
|
||||
|
||||
public void DrawRollover(WorldRenderer wr, Actor self)
|
||||
{
|
||||
if (!Info.Selectable)
|
||||
return;
|
||||
|
||||
var bounds = self.Bounds.Value;
|
||||
|
||||
var xy = new float2(bounds.Left, bounds.Top);
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace OpenRA.Widgets
|
||||
IEnumerable<Actor> SelectActorsInBox(World world, PPos a, PPos b, Func<Actor, bool> cond)
|
||||
{
|
||||
return world.FindUnits(a, b)
|
||||
.Where(x => x.HasTrait<Selectable>() && !world.FogObscures(x) && cond(x))
|
||||
.Where(x => x.HasTrait<Selectable>() && x.Trait<Selectable>().Info.Selectable && !world.FogObscures(x) && cond(x))
|
||||
.GroupBy(x => x.GetSelectionPriority())
|
||||
.OrderByDescending(g => g.Key)
|
||||
.Select(g => g.AsEnumerable())
|
||||
|
||||
@@ -16,37 +16,35 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class Demolish : Activity
|
||||
{
|
||||
Actor target;
|
||||
Target target;
|
||||
int delay;
|
||||
|
||||
public Demolish( Actor target, int delay )
|
||||
public Demolish(Actor target, int delay)
|
||||
{
|
||||
this.target = target;
|
||||
this.target = Target.FromActor(target);
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
|
||||
|
||||
if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) )
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
||||
{
|
||||
// Can't demolish an already dead actor
|
||||
if (target.IsDead())
|
||||
if (!target.IsValid)
|
||||
return;
|
||||
|
||||
// Invulnerable actors can't be demolished
|
||||
var modifier = (float)target.TraitsImplementing<IDamageModifier>()
|
||||
var modifier = (float)target.Actor.TraitsImplementing<IDamageModifier>()
|
||||
.Concat(self.Owner.PlayerActor.TraitsImplementing<IDamageModifier>())
|
||||
.Select(t => t.GetDamageModifier(self, null)).Product();
|
||||
|
||||
if (target.IsInWorld && modifier > 0)
|
||||
target.Kill(self);
|
||||
if (modifier > 0)
|
||||
target.Actor.Kill(self);
|
||||
})));
|
||||
|
||||
return NextActivity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,26 +16,26 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class DonateSupplies : Activity
|
||||
{
|
||||
Actor target;
|
||||
Target target;
|
||||
int payload;
|
||||
|
||||
public DonateSupplies(Actor target, int payload)
|
||||
{
|
||||
this.target = target;
|
||||
this.target = Target.FromActor(target);
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
|
||||
if (!target.OccupiesSpace.OccupiedCells().Any(x => x.First == self.Location))
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
target.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(payload);
|
||||
var targetPlayer = target.Actor.Owner;
|
||||
targetPlayer.PlayerActor.Trait<PlayerResources>().GiveCash(payload);
|
||||
self.Destroy();
|
||||
if (self.World.LocalPlayer == null || self.Owner.Stances[self.World.LocalPlayer] == Stance.Ally)
|
||||
self.World.AddFrameEndTask(w => w.Add(new CashTick(payload, 30, 2, target.CenterLocation, target.Owner.ColorRamp.GetColor(0))));
|
||||
|
||||
if (self.Owner.IsAlliedWith(self.World.RenderPlayer))
|
||||
self.World.AddFrameEndTask(w => w.Add(new CashTick(payload, 30, 2, target.CenterLocation, targetPlayer.ColorRamp.GetColor(0))));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Traits;
|
||||
|
||||
@@ -15,20 +16,38 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
public class Enter : Activity
|
||||
{
|
||||
readonly Actor target;
|
||||
public Enter( Actor target ) { this.target = target; }
|
||||
readonly Target target;
|
||||
readonly Activity inner;
|
||||
|
||||
public override Activity Tick( Actor self )
|
||||
public Enter(Actor target, Activity inner)
|
||||
{
|
||||
if( IsCanceled || target.Destroyed || !target.IsInWorld )
|
||||
this.target = Target.FromActor(target);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var nearest = target.OccupiesSpace.NearestCellTo( mobile.toCell );
|
||||
if( ( nearest - mobile.toCell ).LengthSquared > 2 )
|
||||
return Util.SequenceActivities( new MoveAdjacentTo( Target.FromActor(target) ), this );
|
||||
if (!Util.AdjacentCells(target).Any(c => c == self.Location))
|
||||
return Util.SequenceActivities(new MoveAdjacentTo(target), this);
|
||||
|
||||
return Util.SequenceActivities( mobile.MoveTo( nearest, target ), NextActivity );
|
||||
// Move to the middle of the target, ignoring impassable tiles
|
||||
var mobile = self.Trait<Mobile>();
|
||||
var to = target.CenterLocation;
|
||||
var from = self.CenterLocation;
|
||||
var speed = mobile.MovementSpeedForCell(self, self.Location);
|
||||
var length = speed > 0 ? (int)((to - from).Length * 3 / speed) : 0;
|
||||
|
||||
return Util.SequenceActivities(
|
||||
new Turn(Util.GetFacing(to - from, mobile.Facing)),
|
||||
new Drag(from, to, length),
|
||||
inner,
|
||||
new Turn(Util.GetFacing(from - to, mobile.Facing)),
|
||||
new Drag(to, from, length),
|
||||
NextActivity
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,31 +16,23 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class Infiltrate : Activity
|
||||
{
|
||||
Actor target;
|
||||
public Infiltrate(Actor target) { this.target = target; }
|
||||
Target target;
|
||||
public Infiltrate(Actor target) { this.target = Target.FromActor(target); }
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
|
||||
if (target.Owner == self.Owner) return NextActivity;
|
||||
|
||||
if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) )
|
||||
if (IsCanceled || !target.IsValid || target.Actor.Owner == self.Owner)
|
||||
return NextActivity;
|
||||
|
||||
foreach (var t in target.TraitsImplementing<IAcceptInfiltrator>())
|
||||
t.OnInfiltrate(target, self);
|
||||
foreach (var t in target.Actor.TraitsImplementing<IAcceptInfiltrator>())
|
||||
t.OnInfiltrate(target.Actor, self);
|
||||
|
||||
if (self.HasTrait<DontDestroyWhenInfiltrating>())
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.Destroyed) return;
|
||||
w.Remove(self);
|
||||
});
|
||||
self.World.AddFrameEndTask(w => { if (!self.Destroyed) w.Remove(self); });
|
||||
else
|
||||
self.Destroy();
|
||||
|
||||
if (target.HasTrait<Building>())
|
||||
if (target.Actor.HasTrait<Building>())
|
||||
Sound.PlayToPlayer(self.Owner, "bldginf1.aud");
|
||||
|
||||
return this;
|
||||
|
||||
@@ -17,33 +17,34 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
readonly Target target;
|
||||
|
||||
public MoveAdjacentTo( Target target ) { this.target = target; }
|
||||
public MoveAdjacentTo(Target target) { this.target = target; }
|
||||
|
||||
public override Activity Tick( Actor self )
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if( IsCanceled || !target.IsValid) return NextActivity;
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
var mobile = self.Trait<Mobile>();
|
||||
|
||||
var ps1 = new PathSearch( self.World, mobile.Info, self )
|
||||
var ps1 = new PathSearch(self.World, mobile.Info, self)
|
||||
{
|
||||
checkForBlocked = true,
|
||||
heuristic = location => 0,
|
||||
inReverse = true
|
||||
};
|
||||
|
||||
foreach( var cell in Util.AdjacentCells(target) )
|
||||
foreach (var cell in Util.AdjacentCells(target))
|
||||
{
|
||||
if (cell == self.Location)
|
||||
return NextActivity;
|
||||
else
|
||||
ps1.AddInitialCell( cell );
|
||||
ps1.AddInitialCell(cell);
|
||||
}
|
||||
|
||||
ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );
|
||||
ps1.heuristic = PathSearch.DefaultEstimator(mobile.toCell);
|
||||
var ps2 = PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, target.CenterLocation.ToCPos(), true);
|
||||
var ret = self.World.WorldActor.Trait<PathFinder>().FindBidiPath(ps1, ps2);
|
||||
|
||||
var ps2 = PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, target.CenterLocation.ToCPos(), true );
|
||||
var ret = self.World.WorldActor.Trait<PathFinder>().FindBidiPath( ps1, ps2 );
|
||||
|
||||
return Util.SequenceActivities( mobile.MoveTo( () => ret ), this );
|
||||
return Util.SequenceActivities(mobile.MoveTo(() => ret), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
OpenRA.Mods.RA/Activities/RepairBridge.cs
Normal file
37
OpenRA.Mods.RA/Activities/RepairBridge.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class RepairBridge : Activity
|
||||
{
|
||||
Target target;
|
||||
|
||||
public RepairBridge(Actor target) { this.target = Target.FromActor(target); }
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
var hut = target.Actor.Trait<BridgeHut>();
|
||||
if (hut.BridgeDamageState == DamageState.Undamaged)
|
||||
return NextActivity;
|
||||
|
||||
hut.Repair(self);
|
||||
self.Destroy();
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,22 +15,20 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
class RepairBuilding : Activity
|
||||
{
|
||||
Actor target;
|
||||
Target target;
|
||||
|
||||
public RepairBuilding(Actor target) { this.target = target; }
|
||||
public RepairBuilding(Actor target) { this.target = Target.FromActor(target); }
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
|
||||
if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) )
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
var health = target.Trait<Health>();
|
||||
var health = target.Actor.Trait<Health>();
|
||||
if (health.DamageState == DamageState.Undamaged)
|
||||
return NextActivity;
|
||||
|
||||
target.InflictDamage(self, -health.MaxHP, null);
|
||||
target.Actor.InflictDamage(self, -health.MaxHP, null);
|
||||
self.Destroy();
|
||||
|
||||
return this;
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
@@ -21,6 +24,8 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
public readonly bool Long = false;
|
||||
|
||||
[Desc("Delay (in ticks) between repairing adjacent spans in long bridges")]
|
||||
public readonly int RepairPropagationDelay = 20;
|
||||
|
||||
public readonly ushort Template = 0;
|
||||
public readonly ushort DamagedTemplate = 0;
|
||||
@@ -149,11 +154,6 @@ namespace OpenRA.Mods.RA
|
||||
yield return new Renderable(t.Value, t.Key.ToPPos().ToFloat2(), terrainPalette, Game.CellSize * t.Key.Y);
|
||||
}
|
||||
|
||||
bool IsIntact(Bridge b)
|
||||
{
|
||||
return b != null && !b.self.IsDead();
|
||||
}
|
||||
|
||||
void KillUnitsOnBridge()
|
||||
{
|
||||
foreach (var c in TileSprites[currentTemplate].Keys)
|
||||
@@ -162,35 +162,55 @@ namespace OpenRA.Mods.RA
|
||||
a.Kill(self);
|
||||
}
|
||||
|
||||
bool dead = false;
|
||||
void UpdateState()
|
||||
bool NeighbourIsDeadShore(Bridge neighbour)
|
||||
{
|
||||
// If this is a long bridge next to a destroyed shore piece, we need die to give clean edges to the break
|
||||
if (Info.Long && Health.DamageState != DamageState.Dead &&
|
||||
((southNeighbour != null && Info.ShorePieces.Contains(southNeighbour.Type) && !IsIntact(southNeighbour)) ||
|
||||
(northNeighbour != null && Info.ShorePieces.Contains(northNeighbour.Type) && !IsIntact(northNeighbour))))
|
||||
{
|
||||
self.Kill(self); // this changes the damagestate
|
||||
}
|
||||
var oldTemplate = currentTemplate;
|
||||
var ds = Health.DamageState;
|
||||
currentTemplate = (ds == DamageState.Dead && Info.DestroyedTemplate > 0) ? Info.DestroyedTemplate :
|
||||
(ds >= DamageState.Heavy && Info.DamagedTemplate > 0) ? Info.DamagedTemplate : Info.Template;
|
||||
return neighbour != null && Info.ShorePieces.Contains(neighbour.Type) && neighbour.Health.IsDead;
|
||||
}
|
||||
|
||||
if (Info.Long && ds == DamageState.Dead)
|
||||
bool LongBridgeSegmentIsDead()
|
||||
{
|
||||
// The long bridge artwork requires a hack to display correctly
|
||||
// if the adjacent shore piece is dead
|
||||
if (!Info.Long)
|
||||
return Health.IsDead;
|
||||
|
||||
if (NeighbourIsDeadShore(northNeighbour))
|
||||
return true;
|
||||
|
||||
if (NeighbourIsDeadShore(southNeighbour))
|
||||
return true;
|
||||
|
||||
return Health.IsDead;
|
||||
}
|
||||
|
||||
ushort ChooseTemplate()
|
||||
{
|
||||
if (Info.Long && LongBridgeSegmentIsDead())
|
||||
{
|
||||
// Long bridges have custom art for multiple segments being destroyed
|
||||
bool waterToSouth = !IsIntact(southNeighbour);
|
||||
bool waterToNorth = !IsIntact(northNeighbour);
|
||||
var northIsDead = northNeighbour != null && northNeighbour.LongBridgeSegmentIsDead();
|
||||
var southIsDead = southNeighbour != null && southNeighbour.LongBridgeSegmentIsDead();
|
||||
if (northIsDead && southIsDead)
|
||||
return Info.DestroyedPlusBothTemplate;
|
||||
if (northIsDead)
|
||||
return Info.DestroyedPlusNorthTemplate;
|
||||
if (southIsDead)
|
||||
return Info.DestroyedPlusSouthTemplate;
|
||||
|
||||
if (waterToSouth && waterToNorth)
|
||||
currentTemplate = Info.DestroyedPlusBothTemplate;
|
||||
else if (waterToNorth)
|
||||
currentTemplate = Info.DestroyedPlusNorthTemplate;
|
||||
else if (waterToSouth)
|
||||
currentTemplate = Info.DestroyedPlusSouthTemplate;
|
||||
return Info.DestroyedTemplate;
|
||||
}
|
||||
|
||||
var ds = Health.DamageState;
|
||||
return (ds == DamageState.Dead && Info.DestroyedTemplate > 0) ? Info.DestroyedTemplate :
|
||||
(ds >= DamageState.Heavy && Info.DamagedTemplate > 0) ? Info.DamagedTemplate : Info.Template;
|
||||
}
|
||||
|
||||
bool killedUnits = false;
|
||||
void UpdateState()
|
||||
{
|
||||
var oldTemplate = currentTemplate;
|
||||
|
||||
currentTemplate = ChooseTemplate();
|
||||
if (currentTemplate == oldTemplate)
|
||||
return;
|
||||
|
||||
@@ -198,18 +218,81 @@ namespace OpenRA.Mods.RA
|
||||
foreach (var c in TileSprites[currentTemplate].Keys)
|
||||
self.World.Map.CustomTerrain[c.X, c.Y] = GetTerrainType(c);
|
||||
|
||||
if (ds == DamageState.Dead && !dead)
|
||||
if (LongBridgeSegmentIsDead() && !killedUnits)
|
||||
{
|
||||
dead = true;
|
||||
killedUnits = true;
|
||||
KillUnitsOnBridge();
|
||||
}
|
||||
}
|
||||
|
||||
public void Repair(Actor repairer, bool continueNorth, bool continueSouth)
|
||||
{
|
||||
// Repair self
|
||||
var initialDamage = Health.DamageState;
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (Health.IsDead)
|
||||
{
|
||||
Health.Resurrect(self, repairer);
|
||||
killedUnits = false;
|
||||
KillUnitsOnBridge();
|
||||
}
|
||||
else
|
||||
Health.InflictDamage(self, repairer, -Health.MaxHP, null, true);
|
||||
});
|
||||
|
||||
// Repair adjacent spans (long bridges)
|
||||
if (continueNorth && northNeighbour != null)
|
||||
{
|
||||
var delay = initialDamage == DamageState.Undamaged || NeighbourIsDeadShore(northNeighbour) ?
|
||||
0 : Info.RepairPropagationDelay;
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
||||
northNeighbour.Repair(repairer, true, false))));
|
||||
}
|
||||
|
||||
if (continueSouth && southNeighbour != null)
|
||||
{
|
||||
var delay = initialDamage == DamageState.Undamaged || NeighbourIsDeadShore(southNeighbour) ?
|
||||
0 : Info.RepairPropagationDelay;
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
|
||||
southNeighbour.Repair(repairer, false, true))));
|
||||
}
|
||||
}
|
||||
|
||||
public void DamageStateChanged(Actor self, AttackInfo e)
|
||||
{
|
||||
UpdateState();
|
||||
if (northNeighbour != null) northNeighbour.UpdateState();
|
||||
if (southNeighbour != null) southNeighbour.UpdateState();
|
||||
if (northNeighbour != null)
|
||||
northNeighbour.UpdateState();
|
||||
if (southNeighbour != null)
|
||||
southNeighbour.UpdateState();
|
||||
|
||||
// Need to update the neighbours neighbour to correctly
|
||||
// display the broken shore hack
|
||||
if (Info.ShorePieces.Contains(Type))
|
||||
{
|
||||
if (northNeighbour != null && northNeighbour.northNeighbour != null)
|
||||
northNeighbour.northNeighbour.UpdateState();
|
||||
if (southNeighbour != null && southNeighbour.southNeighbour != null)
|
||||
southNeighbour.southNeighbour.UpdateState();
|
||||
}
|
||||
}
|
||||
|
||||
public DamageState AggregateDamageState()
|
||||
{
|
||||
// Find the worst span damage in the entire bridge
|
||||
var br = this;
|
||||
while (br.northNeighbour != null)
|
||||
br = br.northNeighbour;
|
||||
|
||||
var damage = Health.DamageState;
|
||||
for (var b = br; b != null; b = b.southNeighbour)
|
||||
if (b.Health.DamageState > damage)
|
||||
damage = b.Health.DamageState;
|
||||
|
||||
return damage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
OpenRA.Mods.RA/BridgeHut.cs
Normal file
41
OpenRA.Mods.RA/BridgeHut.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class BridgeHutInfo : ITraitInfo
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new BridgeHut(init); }
|
||||
}
|
||||
|
||||
class BridgeHut
|
||||
{
|
||||
public Bridge bridge;
|
||||
|
||||
public BridgeHut(ActorInitializer init)
|
||||
{
|
||||
bridge = init.Get<ParentActorInit>().value.Trait<Bridge>();
|
||||
}
|
||||
|
||||
public void Repair(Actor repairer)
|
||||
{
|
||||
bridge.Repair(repairer, true, true);
|
||||
}
|
||||
|
||||
public DamageState BridgeDamageState { get { return bridge.AggregateDamageState(); } }
|
||||
}
|
||||
}
|
||||
@@ -85,16 +85,13 @@ namespace OpenRA.Mods.RA
|
||||
// For each subtile in the template
|
||||
for (byte ind = 0; ind < template.Size.X*template.Size.Y; ind++)
|
||||
{
|
||||
// Is this tile actually included in the bridge template?
|
||||
if (!template.Tiles.Keys.Contains(ind))
|
||||
continue;
|
||||
|
||||
// Where do we expect to find the subtile
|
||||
var x = ni + ind % template.Size.X;
|
||||
var y = nj + ind / template.Size.X;
|
||||
|
||||
// This isn't the bridge you're looking for
|
||||
if (!w.Map.IsInMap(x, y) || w.Map.MapTiles.Value[x, y].index != ind)
|
||||
if (!w.Map.IsInMap(x, y) || w.Map.MapTiles.Value[x, y].type != tile ||
|
||||
w.Map.MapTiles.Value[x, y].index != ind)
|
||||
continue;
|
||||
|
||||
subTiles.Add(new CPos(x, y), ind);
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get { yield return new UnitTraitOrderTargeter<C4Demolishable>("C4", 6, "c4", true, false); }
|
||||
get { yield return new TargetTypeOrderTargeter("C4", "C4", 6, "c4", true, false); }
|
||||
}
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued )
|
||||
@@ -52,11 +52,8 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
||||
|
||||
var mobile = self.Trait<Mobile>();
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Enter(order.TargetActor));
|
||||
self.QueueActivity(new Demolish(order.TargetActor, Info.C4Delay));
|
||||
self.QueueActivity(mobile.MoveTo(self.Location, 0));
|
||||
self.QueueActivity(new Enter(order.TargetActor, new Demolish(order.TargetActor, Info.C4Delay)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +62,4 @@ namespace OpenRA.Mods.RA
|
||||
return (order.OrderString == "C4") ? "Attack" : null;
|
||||
}
|
||||
}
|
||||
|
||||
class C4DemolishableInfo : TraitInfo<C4Demolishable> { }
|
||||
class C4Demolishable { }
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued )
|
||||
{
|
||||
if( order.OrderID == "CaptureActor" )
|
||||
if (order.OrderID == "CaptureActor")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
@@ -64,7 +64,8 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
if (order.OrderString == "CaptureActor")
|
||||
{
|
||||
if (!CanCapture(order.TargetActor)) return;
|
||||
if (!CanCapture(order.TargetActor))
|
||||
return;
|
||||
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
||||
|
||||
@@ -76,17 +77,17 @@ namespace OpenRA.Mods.RA
|
||||
bool CanCapture(Actor target)
|
||||
{
|
||||
var c = target.TraitOrDefault<Capturable>();
|
||||
return c != null && ( !c.CaptureInProgress || c.Captor.Owner.Stances[self.Owner] != Stance.Ally );
|
||||
return c != null && (!c.CaptureInProgress || c.Captor.Owner.Stances[self.Owner] != Stance.Ally);
|
||||
}
|
||||
}
|
||||
|
||||
class CaptureOrderTargeter : UnitTraitOrderTargeter<Capturable>
|
||||
class CaptureOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
readonly string[] captureTypes;
|
||||
readonly Func<Actor, bool> useEnterCursor;
|
||||
|
||||
public CaptureOrderTargeter(string[] captureTypes, Func<Actor, bool> useEnterCursor)
|
||||
: base( "CaptureActor", 6, "enter", true, true)
|
||||
: base("CaptureActor", 6, "enter", true, true)
|
||||
{
|
||||
this.captureTypes = captureTypes;
|
||||
this.useEnterCursor = useEnterCursor;
|
||||
@@ -94,19 +95,26 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
{
|
||||
if( !base.CanTargetActor( self, target, forceAttack, forceQueued, ref cursor ) ) return false;
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
var ci = target.Info.Traits.Get<CapturableInfo>();
|
||||
var playerRelationship = self.Owner.Stances[ target.Owner ];
|
||||
var ci = target.Info.Traits.GetOrDefault<CapturableInfo>();
|
||||
if (ci == null)
|
||||
return false;
|
||||
|
||||
if( playerRelationship == Stance.Ally && !ci.AllowAllies ) return false;
|
||||
if( playerRelationship == Stance.Enemy && !ci.AllowEnemies ) return false;
|
||||
if( playerRelationship == Stance.Neutral && !ci.AllowNeutral ) return false;
|
||||
var playerRelationship = self.Owner.Stances[target.Owner];
|
||||
if (playerRelationship == Stance.Ally && !ci.AllowAllies)
|
||||
return false;
|
||||
|
||||
if (playerRelationship == Stance.Enemy && !ci.AllowEnemies)
|
||||
return false;
|
||||
|
||||
if (playerRelationship == Stance.Neutral && !ci.AllowNeutral)
|
||||
return false;
|
||||
|
||||
IsQueued = forceQueued;
|
||||
|
||||
var Info = self.Info.Traits.Get<CapturesInfo>();
|
||||
|
||||
if (captureTypes.Contains(ci.Type))
|
||||
{
|
||||
cursor = (Info.WastedAfterwards) ? (useEnterCursor(target) ? "enter" : "enter-blocked") : "attack";
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new UnitTraitOrderTargeter<Building>("DemoAttack", 5, "attack", true, false) { ForceAttack = false };
|
||||
yield return new TargetTypeOrderTargeter("DemoTruck", "DemoAttack", 5, "attack", true, false) { ForceAttack = false };
|
||||
yield return new DeployOrderTargeter("DemoDeploy", 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace OpenRA.Mods.RA
|
||||
get { yield return new EngineerRepairOrderTargeter(); }
|
||||
}
|
||||
|
||||
public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued )
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if( order.OrderID == "EngineerRepair" )
|
||||
if (order.OrderID == "EngineerRepair")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
@@ -36,41 +36,43 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "EngineerRepair"
|
||||
&& order.TargetActor.GetDamageState() > DamageState.Undamaged) ? "Attack" : null;
|
||||
return (order.OrderString == "EngineerRepair" &&
|
||||
order.TargetActor.GetDamageState() > DamageState.Undamaged) ? "Attack" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "EngineerRepair"
|
||||
&& order.TargetActor.GetDamageState() > DamageState.Undamaged)
|
||||
if (order.OrderString == "EngineerRepair" &&
|
||||
order.TargetActor.GetDamageState() > DamageState.Undamaged)
|
||||
{
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Yellow);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Enter(order.TargetActor));
|
||||
self.QueueActivity(new RepairBuilding(order.TargetActor));
|
||||
self.QueueActivity(new Enter(order.TargetActor, new RepairBuilding(order.TargetActor)));
|
||||
}
|
||||
}
|
||||
|
||||
class EngineerRepairOrderTargeter : UnitTraitOrderTargeter<Building>
|
||||
class EngineerRepairOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
public EngineerRepairOrderTargeter()
|
||||
: base( "EngineerRepair", 6, "goldwrench", false, true ) { }
|
||||
: base("EngineerRepair", 6, "goldwrench", false, true) { }
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
{
|
||||
if( !base.CanTargetActor( self, target, forceAttack, forceQueued, ref cursor ) ) return false;
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
if (!target.HasTrait<EngineerRepairable>())
|
||||
return false;
|
||||
|
||||
if (self.Owner.Stances[ target.Owner ] != Stance.Ally)
|
||||
if (self.Owner.Stances[target.Owner] != Stance.Ally)
|
||||
return false;
|
||||
|
||||
IsQueued = forceQueued;
|
||||
|
||||
if( target.GetDamageState() == DamageState.Undamaged )
|
||||
if (target.GetDamageState() == DamageState.Undamaged)
|
||||
cursor = "goldwrench-blocked";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,21 +34,22 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
public FreeActor(ActorInitializer init, FreeActorInfo info)
|
||||
{
|
||||
if (init.Contains<FreeActorInit>() && !init.Get<FreeActorInit>().value) return;
|
||||
if (init.Contains<FreeActorInit>() && !init.Get<FreeActorInit>().value)
|
||||
return;
|
||||
|
||||
init.self.World.AddFrameEndTask(
|
||||
w =>
|
||||
init.self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
var a = w.CreateActor(info.Actor, new TypeDictionary
|
||||
{
|
||||
var a = w.CreateActor(info.Actor, new TypeDictionary
|
||||
{
|
||||
new LocationInit( init.self.Location + (CVec)info.SpawnOffset ),
|
||||
new OwnerInit( init.self.Owner ),
|
||||
new FacingInit( info.Facing ),
|
||||
});
|
||||
|
||||
if (info.InitialActivity != null)
|
||||
a.QueueActivity(Game.CreateObject<Activity>(info.InitialActivity));
|
||||
new ParentActorInit(init.self),
|
||||
new LocationInit(init.self.Location + (CVec)info.SpawnOffset),
|
||||
new OwnerInit(init.self.Owner),
|
||||
new FacingInit(info.Facing),
|
||||
});
|
||||
|
||||
if (info.InitialActivity != null)
|
||||
a.QueueActivity(Game.CreateObject<Activity>(info.InitialActivity));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +61,11 @@ namespace OpenRA.Mods.RA
|
||||
public FreeActorInit(bool init) { value = init; }
|
||||
public bool Value(World world) { return value; }
|
||||
}
|
||||
|
||||
public class ParentActorInit : IActorInit<Actor>
|
||||
{
|
||||
public readonly Actor value;
|
||||
public ParentActorInit(Actor parent) { value = parent; }
|
||||
public Actor Value(World world) { return value; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +67,7 @@ namespace OpenRA.Mods.RA
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Red);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Enter(order.TargetActor));
|
||||
self.QueueActivity(new Infiltrate(order.TargetActor));
|
||||
self.QueueActivity(new Enter(order.TargetActor, new Infiltrate(order.TargetActor)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,13 +88,14 @@ namespace OpenRA.Mods.RA
|
||||
return false;
|
||||
}
|
||||
|
||||
class InfiltratorOrderTargeter : UnitTraitOrderTargeter<IAcceptInfiltrator>
|
||||
class InfiltratorOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
readonly Func<Actor, bool> useEnterCursor;
|
||||
|
||||
public InfiltratorOrderTargeter(Func<Actor, bool> useEnterCursor) : base("Infiltrate", 7, "enter", true, false)
|
||||
public InfiltratorOrderTargeter(Func<Actor, bool> useEnterCursor)
|
||||
: base("Infiltrate", 7, "enter", true, false)
|
||||
{
|
||||
ForceAttack=false;
|
||||
ForceAttack = false;
|
||||
this.useEnterCursor = useEnterCursor;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,10 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
|
||||
if (!target.HasTrait<IAcceptInfiltrator>())
|
||||
return false;
|
||||
|
||||
if (!useEnterCursor(target))
|
||||
cursor = "enter-blocked";
|
||||
|
||||
|
||||
@@ -109,7 +109,8 @@ namespace OpenRA.Mods.RA.Move
|
||||
return true;
|
||||
|
||||
var blockingActors = world.ActorMap.GetUnitsAt(cell)
|
||||
.Where(x => x != ignoreActor)
|
||||
// Don't fail if the unit is already in this cell
|
||||
.Where(x => x != ignoreActor && x != self)
|
||||
// Neutral/enemy units are blockers. Allied units that are moving are not blockers.
|
||||
.Where(x => blockedByMovers || ((self.Owner.Stances[x.Owner] != Stance.Ally) || !IsMovingInMyDirection(self, x)))
|
||||
.ToList();
|
||||
|
||||
@@ -423,6 +423,9 @@
|
||||
<Compile Include="Buildings\BaseProvider.cs" />
|
||||
<Compile Include="Render\WithSpinner.cs" />
|
||||
<Compile Include="Widgets\Logic\ObserverShroudSelectorLogic.cs" />
|
||||
<Compile Include="RepairsBridges.cs" />
|
||||
<Compile Include="Activities\RepairBridge.cs" />
|
||||
<Compile Include="BridgeHut.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -12,14 +12,14 @@ using System;
|
||||
|
||||
namespace OpenRA.Mods.RA.Orders
|
||||
{
|
||||
public class EnterOrderTargeter<T> : UnitTraitOrderTargeter<T>
|
||||
public class EnterOrderTargeter<T> : UnitOrderTargeter
|
||||
{
|
||||
readonly Func<Actor, bool> canTarget;
|
||||
readonly Func<Actor, bool> useEnterCursor;
|
||||
|
||||
public EnterOrderTargeter( string order, int priority, bool targetEnemy, bool targetAlly,
|
||||
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor )
|
||||
: base( order, priority, "enter", targetEnemy, targetAlly )
|
||||
public EnterOrderTargeter(string order, int priority, bool targetEnemy, bool targetAlly,
|
||||
Func<Actor, bool> canTarget, Func<Actor, bool> useEnterCursor)
|
||||
: base (order, priority, "enter", targetEnemy, targetAlly)
|
||||
{
|
||||
this.canTarget = canTarget;
|
||||
this.useEnterCursor = useEnterCursor;
|
||||
@@ -27,8 +27,15 @@ namespace OpenRA.Mods.RA.Orders
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
{
|
||||
if( !base.CanTargetActor( self, target, forceAttack, forceQueued, ref cursor ) ) return false;
|
||||
if( !canTarget( target ) ) return false;
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
if (!target.HasTrait<T>())
|
||||
return false;
|
||||
|
||||
if (!canTarget(target))
|
||||
return false;
|
||||
|
||||
cursor = useEnterCursor(target) ? "enter" : "enter-blocked";
|
||||
IsQueued = forceQueued;
|
||||
return true;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Orders
|
||||
@@ -57,17 +58,23 @@ namespace OpenRA.Mods.RA.Orders
|
||||
public virtual bool IsQueued { get; protected set; }
|
||||
}
|
||||
|
||||
public class UnitTraitOrderTargeter<T> : UnitOrderTargeter
|
||||
public class TargetTypeOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
public UnitTraitOrderTargeter( string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits )
|
||||
: base( order, priority, cursor, targetEnemyUnits, targetAllyUnits )
|
||||
string targetType;
|
||||
|
||||
public TargetTypeOrderTargeter(string targetType, string order, int priority, string cursor, bool targetEnemyUnits, bool targetAllyUnits)
|
||||
: base(order, priority, cursor, targetEnemyUnits, targetAllyUnits)
|
||||
{
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
{
|
||||
if( !base.CanTargetActor( self, target, forceAttack, forceQueued, ref cursor ) ) return false;
|
||||
if( !target.HasTrait<T>() ) return false;
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
if (!target.TraitsImplementing<ITargetable>().Any(t => t.TargetTypes.Contains(targetType)))
|
||||
return false;
|
||||
|
||||
IsQueued = forceQueued;
|
||||
|
||||
|
||||
96
OpenRA.Mods.RA/RepairsBridges.cs
Normal file
96
OpenRA.Mods.RA/RepairsBridges.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Mods.RA.Buildings;
|
||||
using OpenRA.Mods.RA.Orders;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class RepairsBridgesInfo : TraitInfo<RepairsBridges> {}
|
||||
|
||||
class RepairsBridges : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
{
|
||||
get { yield return new RepairBridgeOrderTargeter(); }
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
|
||||
{
|
||||
if (order.OrderID == "RepairBridge")
|
||||
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString != "RepairBridge")
|
||||
return null;
|
||||
|
||||
var bridge = order.TargetActor.TraitOrDefault<BridgeHut>();
|
||||
if (bridge == null)
|
||||
return null;
|
||||
|
||||
return bridge.BridgeDamageState > DamageState.Undamaged ? "Attack" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "RepairBridge")
|
||||
{
|
||||
var bridge = order.TargetActor.TraitOrDefault<BridgeHut>();
|
||||
if (bridge == null)
|
||||
return;
|
||||
|
||||
if (bridge.BridgeDamageState == DamageState.Undamaged)
|
||||
return;
|
||||
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Yellow);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Enter(order.TargetActor, new RepairBridge(order.TargetActor)));
|
||||
}
|
||||
}
|
||||
|
||||
class RepairBridgeOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
public RepairBridgeOrderTargeter()
|
||||
: base("RepairBridge", 6, "goldwrench", true, true) { }
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
{
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
var bridge = target.TraitOrDefault<BridgeHut>();
|
||||
if (bridge == null)
|
||||
return false;
|
||||
|
||||
// Require force attack to heal partially damaged bridges to avoid unnecessary cursor noise
|
||||
var damage = bridge.BridgeDamageState;
|
||||
if (!forceAttack && damage != DamageState.Dead)
|
||||
return false;
|
||||
|
||||
IsQueued = forceQueued;
|
||||
|
||||
// Can't repair an undamaged bridge
|
||||
if (damage == DamageState.Undamaged)
|
||||
cursor = "goldwrench-blocked";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new UnitTraitOrderTargeter<RenderInfantry>("Disguise", 7, "ability", true, true) { ForceAttack=false };
|
||||
yield return new TargetTypeOrderTargeter("Disguise", "Disguise", 7, "ability", true, true) { ForceAttack=false };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,12 +59,11 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
self.SetTargetLine(Target.FromOrder(order), Color.Yellow);
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new Enter(order.TargetActor));
|
||||
self.QueueActivity(new DonateSupplies(order.TargetActor, Info.Payload));
|
||||
self.QueueActivity(new Enter(order.TargetActor, new DonateSupplies(order.TargetActor, Info.Payload)));
|
||||
}
|
||||
}
|
||||
|
||||
class SupplyTruckOrderTargeter : UnitTraitOrderTargeter<Building>
|
||||
class SupplyTruckOrderTargeter : UnitOrderTargeter
|
||||
{
|
||||
public SupplyTruckOrderTargeter()
|
||||
: base("DeliverSupplies", 5, "enter", false, true)
|
||||
@@ -73,9 +72,14 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public override bool CanTargetActor(Actor self, Actor target, bool forceAttack, bool forceQueued, ref string cursor)
|
||||
{
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor)) return false;
|
||||
if (target.AppearsHostileTo(self)) return false;
|
||||
if (!target.HasTrait<AcceptsSupplies>()) return false;
|
||||
if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor))
|
||||
return false;
|
||||
|
||||
if (target.AppearsHostileTo(self))
|
||||
return false;
|
||||
|
||||
if (!target.HasTrait<AcceptsSupplies>())
|
||||
return false;
|
||||
|
||||
IsQueued = forceQueued;
|
||||
return true;
|
||||
|
||||
@@ -145,6 +145,12 @@ BRIDGE1:
|
||||
Building:
|
||||
Footprint: ____ ____ ____ ____
|
||||
Dimensions: 4,4
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,2
|
||||
|
||||
BRIDGE2:
|
||||
Inherits: ^Bridge
|
||||
@@ -154,6 +160,12 @@ BRIDGE2:
|
||||
Building:
|
||||
Footprint: _____ _____ _____ _____ _____
|
||||
Dimensions: 5,5
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,2
|
||||
|
||||
BRIDGE3:
|
||||
Inherits: ^Bridge
|
||||
@@ -163,6 +175,12 @@ BRIDGE3:
|
||||
Building:
|
||||
Footprint: ______ ______ ______ ______ ______
|
||||
Dimensions: 6,5
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 3,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 1,2
|
||||
|
||||
BRIDGE4:
|
||||
Inherits: ^Bridge
|
||||
@@ -172,6 +190,23 @@ BRIDGE4:
|
||||
Building:
|
||||
Footprint: ______ ______ ______ ______
|
||||
Dimensions: 6,4
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 1,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 3,2
|
||||
|
||||
BRIDGEHUT:
|
||||
Building:
|
||||
Footprint: __ __
|
||||
Dimensions: 2,2
|
||||
Selectable:
|
||||
Selectable: false
|
||||
Bounds: 48,48
|
||||
BridgeHut:
|
||||
TargetableBuilding:
|
||||
TargetTypes: BridgeHut
|
||||
|
||||
C1:
|
||||
Inherits: ^CivInfantry
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
Selectable:
|
||||
Priority: 3
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4
|
||||
Armor:
|
||||
Type: Wood
|
||||
RepairableBuilding:
|
||||
@@ -399,6 +399,3 @@
|
||||
SoundOnDamageTransition:
|
||||
DamagedSound: xplos.aud
|
||||
DestroyedSound: xplobig4.aud
|
||||
Building:
|
||||
Footprint: ______ ______ ______ ______
|
||||
Dimensions: 6,4
|
||||
|
||||
@@ -182,6 +182,7 @@ E6:
|
||||
Passenger:
|
||||
PipType: Yellow
|
||||
EngineerRepair:
|
||||
RepairsBridges:
|
||||
Captures:
|
||||
CaptureTypes: building, husk
|
||||
-AutoTarget:
|
||||
|
||||
@@ -302,6 +302,12 @@ BRIDGE1:
|
||||
Building:
|
||||
Footprint: ____ ____ ____ ____
|
||||
Dimensions: 4,4
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,2
|
||||
|
||||
BRIDGE2:
|
||||
Inherits: ^Bridge
|
||||
@@ -311,6 +317,12 @@ BRIDGE2:
|
||||
Building:
|
||||
Footprint: _____ _____ _____ _____ _____
|
||||
Dimensions: 5,5
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,2
|
||||
|
||||
BRIDGE3:
|
||||
Inherits: ^Bridge
|
||||
@@ -320,6 +332,12 @@ BRIDGE3:
|
||||
Building:
|
||||
Footprint: ______ ______ ______ ______ ______
|
||||
Dimensions: 6,5
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 3,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 1,2
|
||||
|
||||
BRIDGE4:
|
||||
Inherits: ^Bridge
|
||||
@@ -329,6 +347,23 @@ BRIDGE4:
|
||||
Building:
|
||||
Footprint: ______ ______ ______ ______
|
||||
Dimensions: 6,4
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 1,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 3,2
|
||||
|
||||
BRIDGEHUT:
|
||||
Building:
|
||||
Footprint: __ __
|
||||
Dimensions: 2,2
|
||||
Selectable:
|
||||
Selectable: false
|
||||
Bounds: 48,48
|
||||
BridgeHut:
|
||||
TargetableBuilding:
|
||||
TargetTypes: BridgeHut
|
||||
|
||||
C1:
|
||||
Inherits: ^CivInfantry
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
Selectable:
|
||||
Priority: 3
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4
|
||||
Armor:
|
||||
Type: Wood
|
||||
RepairableBuilding:
|
||||
@@ -267,7 +267,6 @@
|
||||
Sellable:
|
||||
Capturable:
|
||||
CapturableBar:
|
||||
C4Demolishable:
|
||||
DebugMuzzlePositions:
|
||||
|
||||
^CivBuilding:
|
||||
@@ -339,7 +338,7 @@
|
||||
Adjacent: 7
|
||||
TerrainTypes: Clear,Road
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4
|
||||
Wall:
|
||||
CrushClasses: wall
|
||||
CrushSound: sandbag2.aud
|
||||
@@ -356,7 +355,6 @@
|
||||
RelativeToTopLeft: yes
|
||||
AutoTargetIgnore:
|
||||
Sellable:
|
||||
C4Demolishable:
|
||||
|
||||
^Tree:
|
||||
Tooltip:
|
||||
@@ -419,10 +417,7 @@
|
||||
TargetTypes: Ground, Water
|
||||
BelowUnits:
|
||||
Health:
|
||||
# HP: 500
|
||||
HP: 500
|
||||
SoundOnDamageTransition:
|
||||
DamagedSound: xplos.aud
|
||||
DestroyedSound: xplobig4.aud
|
||||
Building:
|
||||
Footprint: ______ ______ ______ ______
|
||||
Dimensions: 6,4
|
||||
|
||||
@@ -166,6 +166,7 @@ E6:
|
||||
Passenger:
|
||||
PipType: Yellow
|
||||
EngineerRepair:
|
||||
RepairsBridges:
|
||||
Captures:
|
||||
CaptureTypes: building, husk
|
||||
-AutoTarget:
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
Selectable:
|
||||
Priority: 2
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
@@ -263,6 +263,5 @@
|
||||
Types:Building
|
||||
Sellable:
|
||||
GivesBounty:
|
||||
C4Demolishable:
|
||||
DebugMuzzlePositions:
|
||||
Bib:
|
||||
|
||||
@@ -353,7 +353,7 @@ WALL:
|
||||
#Selectable:
|
||||
# Priority: 1
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4
|
||||
RenderBuildingWall:
|
||||
HasMakeAnimation: false
|
||||
#GivesExperience:
|
||||
|
||||
@@ -232,6 +232,9 @@ BR1:
|
||||
DamagedTemplate: 236
|
||||
DestroyedTemplate: 237
|
||||
SouthOffset: 0,2
|
||||
FreeActor:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,0
|
||||
|
||||
BR2:
|
||||
Inherits: ^Bridge
|
||||
@@ -240,6 +243,9 @@ BR2:
|
||||
DamagedTemplate: 239
|
||||
DestroyedTemplate: 240
|
||||
NorthOffset: 3,0
|
||||
FreeActor:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 1,1
|
||||
|
||||
BR3:
|
||||
Inherits: ^Bridge
|
||||
@@ -264,6 +270,12 @@ BRIDGE1:
|
||||
Building:
|
||||
Footprint: _____ _____ _____
|
||||
Dimensions: 5,3
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,-1
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,1
|
||||
|
||||
BRIDGE2:
|
||||
Inherits: ^Bridge
|
||||
@@ -273,4 +285,21 @@ BRIDGE2:
|
||||
DestroyedTemplate: 134
|
||||
Building:
|
||||
Footprint: _____ _____
|
||||
Dimensions: 5,2
|
||||
Dimensions: 5,2
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,-1
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,1
|
||||
|
||||
BRIDGEHUT:
|
||||
Building:
|
||||
Footprint: __ __
|
||||
Dimensions: 2,2
|
||||
Selectable:
|
||||
Selectable: false
|
||||
Bounds: 48,48
|
||||
BridgeHut:
|
||||
TargetableBuilding:
|
||||
TargetTypes: BridgeHut
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
Selectable:
|
||||
Voice: GenericVoice
|
||||
TargetableUnit:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, Disguise
|
||||
RenderInfantry:
|
||||
AutoTarget:
|
||||
AttackMove:
|
||||
@@ -164,7 +164,7 @@
|
||||
Selectable:
|
||||
Priority: 3
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4, DemoTruck
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
@@ -210,7 +210,7 @@
|
||||
Selectable:
|
||||
Priority: 1
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4, DemoTruck
|
||||
RenderBuildingWall:
|
||||
HasMakeAnimation: false
|
||||
Palette: terrain
|
||||
|
||||
@@ -162,6 +162,7 @@ E6:
|
||||
Passenger:
|
||||
PipType: Yellow
|
||||
EngineerRepair:
|
||||
RepairsBridges:
|
||||
Captures:
|
||||
Sabotage: yes
|
||||
TakeCover:
|
||||
|
||||
@@ -246,7 +246,8 @@ BARL:
|
||||
AutoTargetIgnore:
|
||||
Armor:
|
||||
Type: Light
|
||||
-C4Demolishable:
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground, DemoTruck
|
||||
|
||||
BRL3:
|
||||
Inherits: ^TechBuilding
|
||||
@@ -261,7 +262,8 @@ BRL3:
|
||||
AutoTargetIgnore:
|
||||
Armor:
|
||||
Type: Light
|
||||
-C4Demolishable:
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground, DemoTruck
|
||||
|
||||
MISS:
|
||||
Inherits: ^TechBuilding
|
||||
@@ -320,6 +322,9 @@ BR1:
|
||||
DamagedTemplate: 236
|
||||
DestroyedTemplate: 237
|
||||
SouthOffset: 0,2
|
||||
FreeActor:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,0
|
||||
|
||||
BR2:
|
||||
Inherits: ^Bridge
|
||||
@@ -328,6 +333,9 @@ BR2:
|
||||
DamagedTemplate: 239
|
||||
DestroyedTemplate: 240
|
||||
NorthOffset: 3,0
|
||||
FreeActor:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 1,1
|
||||
|
||||
BR3:
|
||||
Inherits: ^Bridge
|
||||
@@ -352,6 +360,12 @@ BRIDGE1:
|
||||
Building:
|
||||
Footprint: _____ _____ _____
|
||||
Dimensions: 5,3
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,-1
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,1
|
||||
|
||||
BRIDGE2:
|
||||
Inherits: ^Bridge
|
||||
@@ -362,6 +376,12 @@ BRIDGE2:
|
||||
Building:
|
||||
Footprint: _____ _____
|
||||
Dimensions: 5,2
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,-1
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,1
|
||||
|
||||
SBRIDGE1:
|
||||
Inherits: ^SVBridge
|
||||
@@ -372,6 +392,13 @@ SBRIDGE1:
|
||||
Building:
|
||||
Footprint: ___ ___
|
||||
Dimensions: 3,2
|
||||
FreeActor@north:
|
||||
Actor: bridgehut.small
|
||||
SpawnOffset: 1,0
|
||||
FreeActor@south:
|
||||
Actor: bridgehut.small
|
||||
SpawnOffset: 1,1
|
||||
|
||||
SBRIDGE2:
|
||||
Inherits: ^SHBridge
|
||||
Bridge:
|
||||
@@ -381,6 +408,13 @@ SBRIDGE2:
|
||||
Building:
|
||||
Footprint: __ __ __
|
||||
Dimensions: 2,3
|
||||
FreeActor@west:
|
||||
Actor: bridgehut.small
|
||||
SpawnOffset: 0,1
|
||||
FreeActor@east:
|
||||
Actor: bridgehut.small
|
||||
SpawnOffset: 1,1
|
||||
|
||||
SBRIDGE3:
|
||||
Inherits: ^STDBridge
|
||||
Bridge:
|
||||
@@ -390,6 +424,13 @@ SBRIDGE3:
|
||||
Building:
|
||||
Footprint: ____ ____
|
||||
Dimensions: 4,2
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,-1
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,1
|
||||
|
||||
SBRIDGE4:
|
||||
Inherits: ^STDBridge
|
||||
Bridge:
|
||||
@@ -399,6 +440,34 @@ SBRIDGE4:
|
||||
Building:
|
||||
Footprint: ____ ____
|
||||
Dimensions: 4,2
|
||||
FreeActor@north:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 0,-1
|
||||
FreeActor@south:
|
||||
Actor: bridgehut
|
||||
SpawnOffset: 2,1
|
||||
|
||||
BRIDGEHUT:
|
||||
Building:
|
||||
Footprint: __ __
|
||||
Dimensions: 2,2
|
||||
Selectable:
|
||||
Selectable: false
|
||||
Bounds: 48,48
|
||||
BridgeHut:
|
||||
TargetableBuilding:
|
||||
TargetTypes: BridgeHut
|
||||
|
||||
BRIDGEHUT.small:
|
||||
Building:
|
||||
Footprint: _
|
||||
Dimensions: 1,1
|
||||
Selectable:
|
||||
Selectable: false
|
||||
Bounds: 24,24
|
||||
BridgeHut:
|
||||
TargetableBuilding:
|
||||
TargetTypes: BridgeHut
|
||||
|
||||
#Desert Terrain Expansion
|
||||
V20:
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
Selectable:
|
||||
Voice: GenericVoice
|
||||
TargetableUnit:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, Disguise
|
||||
RenderInfantry:
|
||||
AutoTarget:
|
||||
DebugRetiliateAgainstAggressor:
|
||||
@@ -196,7 +196,7 @@
|
||||
Selectable:
|
||||
Priority: 3
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4, DemoTruck
|
||||
Building:
|
||||
Dimensions: 1,1
|
||||
Footprint: x
|
||||
@@ -227,7 +227,6 @@
|
||||
AcceptsSupplies:
|
||||
GivesBounty:
|
||||
UpdatesPlayerStatistics:
|
||||
C4Demolishable:
|
||||
DebugMuzzlePositions:
|
||||
|
||||
^Wall:
|
||||
@@ -249,7 +248,7 @@
|
||||
Selectable:
|
||||
Priority: 1
|
||||
TargetableBuilding:
|
||||
TargetTypes: Ground
|
||||
TargetTypes: Ground, C4, DemoTruck
|
||||
RenderBuildingWall:
|
||||
HasMakeAnimation: false
|
||||
Palette: terrain
|
||||
@@ -262,7 +261,6 @@
|
||||
Types:Wall
|
||||
Sellable:
|
||||
UpdatesPlayerStatistics:
|
||||
C4Demolishable:
|
||||
|
||||
^TechBuilding:
|
||||
Inherits: ^Building
|
||||
|
||||
@@ -167,6 +167,7 @@ E6:
|
||||
Passenger:
|
||||
PipType: Yellow
|
||||
EngineerRepair:
|
||||
RepairsBridges:
|
||||
Captures:
|
||||
TakeCover:
|
||||
-AutoTarget:
|
||||
|
||||
Reference in New Issue
Block a user