Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repairable bridges #3063

Merged
merged 9 commits into from
Apr 15, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions OpenRA.Game/Orders/UnitOrderGenerator.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@ public string GetCursor(World world, CPos xy, MouseInput mi)
.OrderByDescending(a => a.SelectionPriority()) .OrderByDescending(a => a.SelectionPriority())
.FirstOrDefault(); .FirstOrDefault();


if (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()) if (underCursor != null && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()))
if (underCursor != null && underCursor.HasTrait<Selectable>()) {
var selectable = underCursor.TraitOrDefault<Selectable>();
if (selectable != null && selectable.Info.Selectable)
useSelect = true; useSelect = true;
}


var orders = world.Selection.Actors var orders = world.Selection.Actors
.Select(a => OrderForUnit(a, xy, mi, underCursor)) .Select(a => OrderForUnit(a, xy, mi, underCursor))
Expand Down
29 changes: 29 additions & 0 deletions OpenRA.Game/Traits/Health.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -69,6 +69,35 @@ public DamageState DamageState
} }
} }


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) 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! */ if (IsDead) return; /* overkill! don't count extra hits as more kills! */
Expand Down
16 changes: 14 additions & 2 deletions OpenRA.Game/Traits/Selectable.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,21 +16,30 @@ namespace OpenRA.Traits
{ {
public class SelectableInfo : ITraitInfo public class SelectableInfo : ITraitInfo
{ {
public readonly bool Selectable = true;
public readonly int Priority = 10; public readonly int Priority = 10;
public readonly int[] Bounds = null; public readonly int[] Bounds = null;
[VoiceReference] public readonly string Voice = 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 class Selectable : IPostRenderSelection
{ {
public SelectableInfo Info;
Actor self; 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) public void RenderAfterWorld(WorldRenderer wr)
{ {
if (!Info.Selectable)
return;

var bounds = self.Bounds.Value; var bounds = self.Bounds.Value;


var xy = new float2(bounds.Left, bounds.Top); var xy = new float2(bounds.Left, bounds.Top);
Expand All @@ -44,6 +53,9 @@ public void RenderAfterWorld(WorldRenderer wr)


public void DrawRollover(WorldRenderer wr, Actor self) public void DrawRollover(WorldRenderer wr, Actor self)
{ {
if (!Info.Selectable)
return;

var bounds = self.Bounds.Value; var bounds = self.Bounds.Value;


var xy = new float2(bounds.Left, bounds.Top); var xy = new float2(bounds.Left, bounds.Top);
Expand Down
2 changes: 1 addition & 1 deletion OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public override bool HandleKeyPress(KeyInput e)
IEnumerable<Actor> SelectActorsInBox(World world, PPos a, PPos b, Func<Actor, bool> cond) IEnumerable<Actor> SelectActorsInBox(World world, PPos a, PPos b, Func<Actor, bool> cond)
{ {
return world.FindUnits(a, b) 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()) .GroupBy(x => x.GetSelectionPriority())
.OrderByDescending(g => g.Key) .OrderByDescending(g => g.Key)
.Select(g => g.AsEnumerable()) .Select(g => g.AsEnumerable())
Expand Down
20 changes: 9 additions & 11 deletions OpenRA.Mods.RA/Activities/Demolish.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,37 +16,35 @@ namespace OpenRA.Mods.RA.Activities
{ {
class Demolish : Activity class Demolish : Activity
{ {
Actor target; Target target;
int delay; 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; this.delay = delay;
} }


public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled || !target.IsValid)
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;

if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) )
return NextActivity; return NextActivity;


self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () => self.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, () =>
{ {
// Can't demolish an already dead actor // Can't demolish an already dead actor
if (target.IsDead()) if (!target.IsValid)
return; return;


// Invulnerable actors can't be demolished // 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>()) .Concat(self.Owner.PlayerActor.TraitsImplementing<IDamageModifier>())
.Select(t => t.GetDamageModifier(self, null)).Product(); .Select(t => t.GetDamageModifier(self, null)).Product();


if (target.IsInWorld && modifier > 0) if (modifier > 0)
target.Kill(self); target.Actor.Kill(self);
}))); })));

return NextActivity; return NextActivity;
} }
} }
Expand Down
16 changes: 8 additions & 8 deletions OpenRA.Mods.RA/Activities/DonateSupplies.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,26 +16,26 @@ namespace OpenRA.Mods.RA.Activities
{ {
class DonateSupplies : Activity class DonateSupplies : Activity
{ {
Actor target; Target target;
int payload; int payload;


public DonateSupplies(Actor target, int payload) public DonateSupplies(Actor target, int payload)
{ {
this.target = target; this.target = Target.FromActor(target);
this.payload = payload; this.payload = payload;
} }


public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled || !target.IsValid)
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if (!target.OccupiesSpace.OccupiedCells().Any(x => x.First == self.Location))
return NextActivity; return NextActivity;


target.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(payload); var targetPlayer = target.Actor.Owner;
targetPlayer.PlayerActor.Trait<PlayerResources>().GiveCash(payload);
self.Destroy(); 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; return this;
} }
Expand Down
35 changes: 27 additions & 8 deletions OpenRA.Mods.RA/Activities/Enter.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,27 +8,46 @@
*/ */
#endregion #endregion


using System.Linq;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.Traits; using OpenRA.Traits;


namespace OpenRA.Mods.RA.Activities namespace OpenRA.Mods.RA.Activities
{ {
public class Enter : Activity public class Enter : Activity
{ {
readonly Actor target; readonly Target target;
public Enter( Actor target ) { this.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; return NextActivity;


if (!Util.AdjacentCells(target).Any(c => c == self.Location))
return Util.SequenceActivities(new MoveAdjacentTo(target), this);

// Move to the middle of the target, ignoring impassable tiles
var mobile = self.Trait<Mobile>(); var mobile = self.Trait<Mobile>();
var nearest = target.OccupiesSpace.NearestCellTo( mobile.toCell ); var to = target.CenterLocation;
if( ( nearest - mobile.toCell ).LengthSquared > 2 ) var from = self.CenterLocation;
return Util.SequenceActivities( new MoveAdjacentTo( Target.FromActor(target) ), this ); var speed = mobile.MovementSpeedForCell(self, self.Location);
var length = speed > 0 ? (int)((to - from).Length * 3 / speed) : 0;


return Util.SequenceActivities( mobile.MoveTo( nearest, target ), NextActivity ); 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
);
} }
} }
} }
22 changes: 7 additions & 15 deletions OpenRA.Mods.RA/Activities/Infiltrate.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,31 +16,23 @@ namespace OpenRA.Mods.RA.Activities
{ {
class Infiltrate : Activity class Infiltrate : Activity
{ {
Actor target; Target target;
public Infiltrate(Actor target) { this.target = target; } public Infiltrate(Actor target) { this.target = Target.FromActor(target); }


public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled || !target.IsValid || target.Actor.Owner == self.Owner)
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 ) )
return NextActivity; return NextActivity;


foreach (var t in target.TraitsImplementing<IAcceptInfiltrator>()) foreach (var t in target.Actor.TraitsImplementing<IAcceptInfiltrator>())
t.OnInfiltrate(target, self); t.OnInfiltrate(target.Actor, self);


if (self.HasTrait<DontDestroyWhenInfiltrating>()) if (self.HasTrait<DontDestroyWhenInfiltrating>())
self.World.AddFrameEndTask(w => self.World.AddFrameEndTask(w => { if (!self.Destroyed) w.Remove(self); });
{
if (self.Destroyed) return;
w.Remove(self);
});
else else
self.Destroy(); self.Destroy();


if (target.HasTrait<Building>()) if (target.Actor.HasTrait<Building>())
Sound.PlayToPlayer(self.Owner, "bldginf1.aud"); Sound.PlayToPlayer(self.Owner, "bldginf1.aud");


return this; return this;
Expand Down
25 changes: 13 additions & 12 deletions OpenRA.Mods.RA/Activities/MoveAdjacentTo.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,33 +17,34 @@ public class MoveAdjacentTo : Activity
{ {
readonly Target target; 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 mobile = self.Trait<Mobile>();

var ps1 = new PathSearch(self.World, mobile.Info, self)
var ps1 = new PathSearch( self.World, mobile.Info, self )
{ {
checkForBlocked = true, checkForBlocked = true,
heuristic = location => 0, heuristic = location => 0,
inReverse = true inReverse = true
}; };


foreach( var cell in Util.AdjacentCells(target) ) foreach (var cell in Util.AdjacentCells(target))
{
if (cell == self.Location) if (cell == self.Location)
return NextActivity; return NextActivity;
else else
ps1.AddInitialCell( cell ); ps1.AddInitialCell(cell);

}
ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );


var ps2 = PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, target.CenterLocation.ToCPos(), true ); ps1.heuristic = PathSearch.DefaultEstimator(mobile.toCell);
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 changes: 37 additions & 0 deletions OpenRA.Mods.RA/Activities/RepairBridge.cs
Original file line number Original file line Diff line number Diff line change
@@ -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;
}
}
}
12 changes: 5 additions & 7 deletions OpenRA.Mods.RA/Activities/RepairBuilding.cs
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -15,22 +15,20 @@ namespace OpenRA.Mods.RA.Activities
{ {
class RepairBuilding : Activity 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) public override Activity Tick(Actor self)
{ {
if (IsCanceled) return NextActivity; if (IsCanceled || !target.IsValid)
if (target == null || !target.IsInWorld || target.IsDead()) return NextActivity;
if( !target.OccupiesSpace.OccupiedCells().Any( x => x.First == self.Location ) )
return NextActivity; return NextActivity;


var health = target.Trait<Health>(); var health = target.Actor.Trait<Health>();
if (health.DamageState == DamageState.Undamaged) if (health.DamageState == DamageState.Undamaged)
return NextActivity; return NextActivity;


target.InflictDamage(self, -health.MaxHP, null); target.Actor.InflictDamage(self, -health.MaxHP, null);
self.Destroy(); self.Destroy();


return this; return this;
Expand Down
Loading