diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index f24de9b9c3..75d5fe3391 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -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()) + if (underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any())) + { + var selectable = underCursor.TraitOrDefault(); + if (selectable != null && selectable.Info.Selectable) useSelect = true; + } var orders = world.Selection.Actors .Select(a => OrderForUnit(a, xy, mi, underCursor)) diff --git a/OpenRA.Game/Traits/Health.cs b/OpenRA.Game/Traits/Health.cs index 15cc0e12bb..f62c979b71 100755 --- a/OpenRA.Game/Traits/Health.cs +++ b/OpenRA.Game/Traits/Health.cs @@ -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() + .Concat(self.Owner.PlayerActor.TraitsImplementing())) + nd.Damaged(self, ai); + + foreach (var nd in self.TraitsImplementing()) + nd.DamageStateChanged(self, ai); + + if (repairer != null && repairer.IsInWorld && !repairer.IsDead()) + foreach (var nd in repairer.TraitsImplementing() + .Concat(repairer.Owner.PlayerActor.TraitsImplementing())) + 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! */ diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 22562f6382..9fbaf02b4d 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -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); diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs index b58609031b..4debabcfa1 100644 --- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs @@ -184,7 +184,7 @@ namespace OpenRA.Widgets IEnumerable SelectActorsInBox(World world, PPos a, PPos b, Func cond) { return world.FindUnits(a, b) - .Where(x => x.HasTrait() && !world.FogObscures(x) && cond(x)) + .Where(x => x.HasTrait() && x.Trait().Info.Selectable && !world.FogObscures(x) && cond(x)) .GroupBy(x => x.GetSelectionPriority()) .OrderByDescending(g => g.Key) .Select(g => g.AsEnumerable()) diff --git a/OpenRA.Mods.RA/Activities/Demolish.cs b/OpenRA.Mods.RA/Activities/Demolish.cs index d42ccd8cc9..2d9a9e0b26 100644 --- a/OpenRA.Mods.RA/Activities/Demolish.cs +++ b/OpenRA.Mods.RA/Activities/Demolish.cs @@ -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() + var modifier = (float)target.Actor.TraitsImplementing() .Concat(self.Owner.PlayerActor.TraitsImplementing()) .Select(t => t.GetDamageModifier(self, null)).Product(); - if (target.IsInWorld && modifier > 0) - target.Kill(self); + if (modifier > 0) + target.Actor.Kill(self); }))); + return NextActivity; } } diff --git a/OpenRA.Mods.RA/Activities/DonateSupplies.cs b/OpenRA.Mods.RA/Activities/DonateSupplies.cs index ea9d1e54f4..7a805cc826 100644 --- a/OpenRA.Mods.RA/Activities/DonateSupplies.cs +++ b/OpenRA.Mods.RA/Activities/DonateSupplies.cs @@ -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().GiveCash(payload); + var targetPlayer = target.Actor.Owner; + targetPlayer.PlayerActor.Trait().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; } diff --git a/OpenRA.Mods.RA/Activities/Enter.cs b/OpenRA.Mods.RA/Activities/Enter.cs index 75c6c27d3b..652e970c63 100755 --- a/OpenRA.Mods.RA/Activities/Enter.cs +++ b/OpenRA.Mods.RA/Activities/Enter.cs @@ -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(); - 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(); + 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 + ); } } } diff --git a/OpenRA.Mods.RA/Activities/Infiltrate.cs b/OpenRA.Mods.RA/Activities/Infiltrate.cs index b5d82cd3cc..fc9c9cdbdd 100644 --- a/OpenRA.Mods.RA/Activities/Infiltrate.cs +++ b/OpenRA.Mods.RA/Activities/Infiltrate.cs @@ -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()) - t.OnInfiltrate(target, self); + foreach (var t in target.Actor.TraitsImplementing()) + t.OnInfiltrate(target.Actor, self); if (self.HasTrait()) - 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()) + if (target.Actor.HasTrait()) Sound.PlayToPlayer(self.Owner, "bldginf1.aud"); return this; diff --git a/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs b/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs index 1c07b6d2de..3615d40485 100755 --- a/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs +++ b/OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs @@ -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(); - - 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().FindBidiPath(ps1, ps2); - var ps2 = PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, target.CenterLocation.ToCPos(), true ); - var ret = self.World.WorldActor.Trait().FindBidiPath( ps1, ps2 ); - - return Util.SequenceActivities( mobile.MoveTo( () => ret ), this ); + return Util.SequenceActivities(mobile.MoveTo(() => ret), this); } } } diff --git a/OpenRA.Mods.RA/Activities/RepairBridge.cs b/OpenRA.Mods.RA/Activities/RepairBridge.cs new file mode 100644 index 0000000000..90377a47e1 --- /dev/null +++ b/OpenRA.Mods.RA/Activities/RepairBridge.cs @@ -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(); + if (hut.BridgeDamageState == DamageState.Undamaged) + return NextActivity; + + hut.Repair(self); + self.Destroy(); + + return this; + } + } +} diff --git a/OpenRA.Mods.RA/Activities/RepairBuilding.cs b/OpenRA.Mods.RA/Activities/RepairBuilding.cs index 54ffdcad37..8e5e4f4bc6 100644 --- a/OpenRA.Mods.RA/Activities/RepairBuilding.cs +++ b/OpenRA.Mods.RA/Activities/RepairBuilding.cs @@ -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(); + var health = target.Actor.Trait(); if (health.DamageState == DamageState.Undamaged) return NextActivity; - target.InflictDamage(self, -health.MaxHP, null); + target.Actor.InflictDamage(self, -health.MaxHP, null); self.Destroy(); return this; diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index b98df7974f..495e006ce6 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -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; } } } diff --git a/OpenRA.Mods.RA/BridgeHut.cs b/OpenRA.Mods.RA/BridgeHut.cs new file mode 100644 index 0000000000..b55590bf6e --- /dev/null +++ b/OpenRA.Mods.RA/BridgeHut.cs @@ -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().value.Trait(); + } + + public void Repair(Actor repairer) + { + bridge.Repair(repairer, true, true); + } + + public DamageState BridgeDamageState { get { return bridge.AggregateDamageState(); } } + } +} diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs index 8e0df7e4dc..c3a187b921 100644 --- a/OpenRA.Mods.RA/BridgeLayer.cs +++ b/OpenRA.Mods.RA/BridgeLayer.cs @@ -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); diff --git a/OpenRA.Mods.RA/C4Demolition.cs b/OpenRA.Mods.RA/C4Demolition.cs index 24c2e29483..f200ef8bad 100644 --- a/OpenRA.Mods.RA/C4Demolition.cs +++ b/OpenRA.Mods.RA/C4Demolition.cs @@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA public IEnumerable Orders { - get { yield return new UnitTraitOrderTargeter("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(); 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 { } - class C4Demolishable { } } diff --git a/OpenRA.Mods.RA/Captures.cs b/OpenRA.Mods.RA/Captures.cs index 8f3700b4ef..08b1383e48 100644 --- a/OpenRA.Mods.RA/Captures.cs +++ b/OpenRA.Mods.RA/Captures.cs @@ -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(); - 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 + class CaptureOrderTargeter : UnitOrderTargeter { readonly string[] captureTypes; readonly Func useEnterCursor; public CaptureOrderTargeter(string[] captureTypes, Func 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(); - var playerRelationship = self.Owner.Stances[ target.Owner ]; + var ci = target.Info.Traits.GetOrDefault(); + 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(); - if (captureTypes.Contains(ci.Type)) { cursor = (Info.WastedAfterwards) ? (useEnterCursor(target) ? "enter" : "enter-blocked") : "attack"; diff --git a/OpenRA.Mods.RA/DemoTruck.cs b/OpenRA.Mods.RA/DemoTruck.cs index 9f20a4d330..895a38283c 100644 --- a/OpenRA.Mods.RA/DemoTruck.cs +++ b/OpenRA.Mods.RA/DemoTruck.cs @@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA { get { - yield return new UnitTraitOrderTargeter("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); } } diff --git a/OpenRA.Mods.RA/EngineerRepair.cs b/OpenRA.Mods.RA/EngineerRepair.cs index 92d4a055e8..d8cfe5a793 100644 --- a/OpenRA.Mods.RA/EngineerRepair.cs +++ b/OpenRA.Mods.RA/EngineerRepair.cs @@ -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 + 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()) 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; } } diff --git a/OpenRA.Mods.RA/FreeActor.cs b/OpenRA.Mods.RA/FreeActor.cs index cab41feb88..fb5199e333 100644 --- a/OpenRA.Mods.RA/FreeActor.cs +++ b/OpenRA.Mods.RA/FreeActor.cs @@ -34,21 +34,22 @@ namespace OpenRA.Mods.RA { public FreeActor(ActorInitializer init, FreeActorInfo info) { - if (init.Contains() && !init.Get().value) return; + if (init.Contains() && !init.Get().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(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(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 + { + public readonly Actor value; + public ParentActorInit(Actor parent) { value = parent; } + public Actor Value(World world) { return value; } + } } diff --git a/OpenRA.Mods.RA/Infiltrates.cs b/OpenRA.Mods.RA/Infiltrates.cs index abd59a6b75..1f684c834b 100644 --- a/OpenRA.Mods.RA/Infiltrates.cs +++ b/OpenRA.Mods.RA/Infiltrates.cs @@ -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 + class InfiltratorOrderTargeter : UnitOrderTargeter { readonly Func useEnterCursor; - public InfiltratorOrderTargeter(Func useEnterCursor) : base("Infiltrate", 7, "enter", true, false) + public InfiltratorOrderTargeter(Func 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()) + return false; + if (!useEnterCursor(target)) cursor = "enter-blocked"; diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 86b1757737..a3ab8fd27c 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -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(); diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index b9a2febadd..b4d529fd2d 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -423,6 +423,9 @@ + + + diff --git a/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs b/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs index 076ae61f19..8f314e5381 100755 --- a/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs +++ b/OpenRA.Mods.RA/Orders/EnterBuildingOrderTargeter.cs @@ -12,14 +12,14 @@ using System; namespace OpenRA.Mods.RA.Orders { - public class EnterOrderTargeter : UnitTraitOrderTargeter + public class EnterOrderTargeter : UnitOrderTargeter { readonly Func canTarget; readonly Func useEnterCursor; - public EnterOrderTargeter( string order, int priority, bool targetEnemy, bool targetAlly, - Func canTarget, Func useEnterCursor ) - : base( order, priority, "enter", targetEnemy, targetAlly ) + public EnterOrderTargeter(string order, int priority, bool targetEnemy, bool targetAlly, + Func canTarget, Func 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()) + return false; + + if (!canTarget(target)) + return false; + cursor = useEnterCursor(target) ? "enter" : "enter-blocked"; IsQueued = forceQueued; return true; diff --git a/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs b/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs index 5acf4d9b91..f0e4d101d4 100755 --- a/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs +++ b/OpenRA.Mods.RA/Orders/UnitOrderTargeter.cs @@ -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 : 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() ) return false; + if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor)) + return false; + + if (!target.TraitsImplementing().Any(t => t.TargetTypes.Contains(targetType))) + return false; IsQueued = forceQueued; diff --git a/OpenRA.Mods.RA/RepairsBridges.cs b/OpenRA.Mods.RA/RepairsBridges.cs new file mode 100644 index 0000000000..08fa795f89 --- /dev/null +++ b/OpenRA.Mods.RA/RepairsBridges.cs @@ -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 {} + + class RepairsBridges : IIssueOrder, IResolveOrder, IOrderVoice + { + public IEnumerable 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(); + 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(); + 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(); + 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; + } + } + } +} diff --git a/OpenRA.Mods.RA/Spy.cs b/OpenRA.Mods.RA/Spy.cs index 29d05d483d..083769cbac 100644 --- a/OpenRA.Mods.RA/Spy.cs +++ b/OpenRA.Mods.RA/Spy.cs @@ -84,7 +84,7 @@ namespace OpenRA.Mods.RA { get { - yield return new UnitTraitOrderTargeter("Disguise", 7, "ability", true, true) { ForceAttack=false }; + yield return new TargetTypeOrderTargeter("Disguise", "Disguise", 7, "ability", true, true) { ForceAttack=false }; } } diff --git a/OpenRA.Mods.RA/SupplyTruck.cs b/OpenRA.Mods.RA/SupplyTruck.cs index b14084f622..2253bc3141 100644 --- a/OpenRA.Mods.RA/SupplyTruck.cs +++ b/OpenRA.Mods.RA/SupplyTruck.cs @@ -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 + 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()) return false; + if (!base.CanTargetActor(self, target, forceAttack, forceQueued, ref cursor)) + return false; + + if (target.AppearsHostileTo(self)) + return false; + + if (!target.HasTrait()) + return false; IsQueued = forceQueued; return true; diff --git a/mods/cnc-classic/rules/civilian.yaml b/mods/cnc-classic/rules/civilian.yaml index 5eb8bb9d40..6f16f6ac76 100644 --- a/mods/cnc-classic/rules/civilian.yaml +++ b/mods/cnc-classic/rules/civilian.yaml @@ -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 diff --git a/mods/cnc-classic/rules/defaults.yaml b/mods/cnc-classic/rules/defaults.yaml index c3437f55f7..0418b2f474 100644 --- a/mods/cnc-classic/rules/defaults.yaml +++ b/mods/cnc-classic/rules/defaults.yaml @@ -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 diff --git a/mods/cnc-classic/rules/infantry.yaml b/mods/cnc-classic/rules/infantry.yaml index 254ef72d58..fa99a1afae 100644 --- a/mods/cnc-classic/rules/infantry.yaml +++ b/mods/cnc-classic/rules/infantry.yaml @@ -182,6 +182,7 @@ E6: Passenger: PipType: Yellow EngineerRepair: + RepairsBridges: Captures: CaptureTypes: building, husk -AutoTarget: diff --git a/mods/cnc/rules/civilian.yaml b/mods/cnc/rules/civilian.yaml index a9e052898b..17aa688b0c 100644 --- a/mods/cnc/rules/civilian.yaml +++ b/mods/cnc/rules/civilian.yaml @@ -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 diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 7615dfcc2c..0e4b262346 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -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 diff --git a/mods/cnc/rules/infantry.yaml b/mods/cnc/rules/infantry.yaml index fdda163d5f..d25fb54bd9 100644 --- a/mods/cnc/rules/infantry.yaml +++ b/mods/cnc/rules/infantry.yaml @@ -166,6 +166,7 @@ E6: Passenger: PipType: Yellow EngineerRepair: + RepairsBridges: Captures: CaptureTypes: building, husk -AutoTarget: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 6a9c995faf..769ad3fe24 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -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: diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index c29e1c67da..625a333ffb 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -353,7 +353,7 @@ WALL: #Selectable: # Priority: 1 TargetableBuilding: - TargetTypes: Ground + TargetTypes: Ground, C4 RenderBuildingWall: HasMakeAnimation: false #GivesExperience: diff --git a/mods/ra-classic/rules/civilian.yaml b/mods/ra-classic/rules/civilian.yaml index 5f6e996055..48caa6cc2e 100644 --- a/mods/ra-classic/rules/civilian.yaml +++ b/mods/ra-classic/rules/civilian.yaml @@ -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 \ No newline at end of file + 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 diff --git a/mods/ra-classic/rules/defaults.yaml b/mods/ra-classic/rules/defaults.yaml index 35bfbca04e..ecf1617fcd 100644 --- a/mods/ra-classic/rules/defaults.yaml +++ b/mods/ra-classic/rules/defaults.yaml @@ -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 diff --git a/mods/ra-classic/rules/infantry.yaml b/mods/ra-classic/rules/infantry.yaml index d4c80ef26d..cfe1f3d2a6 100644 --- a/mods/ra-classic/rules/infantry.yaml +++ b/mods/ra-classic/rules/infantry.yaml @@ -162,6 +162,7 @@ E6: Passenger: PipType: Yellow EngineerRepair: + RepairsBridges: Captures: Sabotage: yes TakeCover: diff --git a/mods/ra/rules/civilian.yaml b/mods/ra/rules/civilian.yaml index eadc86ec7e..11499c8093 100644 --- a/mods/ra/rules/civilian.yaml +++ b/mods/ra/rules/civilian.yaml @@ -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: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index b06075f5c2..954c4a685e 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -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 diff --git a/mods/ra/rules/infantry.yaml b/mods/ra/rules/infantry.yaml index 0c0da76fb2..b61d8623bf 100644 --- a/mods/ra/rules/infantry.yaml +++ b/mods/ra/rules/infantry.yaml @@ -167,6 +167,7 @@ E6: Passenger: PipType: Yellow EngineerRepair: + RepairsBridges: Captures: TakeCover: -AutoTarget: