Merge pull request #6821 from penev92/bleed_sandworm

Closes #2245
This commit is contained in:
Matthias Mailänder
2014-12-13 14:16:55 +01:00
21 changed files with 482 additions and 36 deletions

View File

@@ -26,6 +26,9 @@ namespace OpenRA.Mods.RA
public readonly string Cursor = "attack";
public readonly string OutsideRangeCursor = "attackoutsiderange";
[Desc("Does the attack type require the attacker to enter the target's cell?")]
public readonly bool AttackRequiresEnteringCell = false;
public abstract object Create(ActorInitializer init);
}
@@ -35,15 +38,16 @@ namespace OpenRA.Mods.RA
public IEnumerable<Armament> Armaments { get { return GetArmaments(); } }
protected Lazy<IFacing> facing;
protected Lazy<Building> building;
protected Lazy<IPositionable> positionable;
protected Func<IEnumerable<Armament>> GetArmaments;
readonly Actor self;
readonly AttackBaseInfo info;
public readonly AttackBaseInfo Info;
public AttackBase(Actor self, AttackBaseInfo info)
{
this.self = self;
this.info = info;
Info = info;
var armaments = Exts.Lazy(() => self.TraitsImplementing<Armament>()
.Where(a => info.Armaments.Contains(a.Info.Name)));
@@ -52,6 +56,7 @@ namespace OpenRA.Mods.RA
facing = Exts.Lazy(() => self.TraitOrDefault<IFacing>());
building = Exts.Lazy(() => self.TraitOrDefault<Building>());
positionable = Exts.Lazy(() => self.Trait<IPositionable>());
}
protected virtual bool CanAttack(Actor self, Target target)
@@ -59,6 +64,9 @@ namespace OpenRA.Mods.RA
if (!self.IsInWorld)
return false;
if (!HasAnyValidWeapons(target))
return false;
// Building is under construction or is being sold
if (building.Value != null && !building.Value.BuildComplete)
return false;
@@ -135,7 +143,17 @@ namespace OpenRA.Mods.RA
public abstract Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove);
public bool HasAnyValidWeapons(Target t) { return Armaments.Any(a => a.Weapon.IsValidAgainst(t, self.World, self)); }
public bool HasAnyValidWeapons(Target t)
{
if (Info.AttackRequiresEnteringCell)
{
if (!positionable.Value.CanEnterCell(t.Actor.Location, null, false))
return false;
}
return Armaments.Any(a => a.Weapon.IsValidAgainst(t, self.World, self));
}
public WRange GetMaximumRange()
{
return Armaments.Select(a => a.Weapon.Range).Append(WRange.Zero).Max();
@@ -179,8 +197,8 @@ namespace OpenRA.Mods.RA
var a = ab.ChooseArmamentForTarget(target);
cursor = a != null && !target.IsInRange(self.CenterPosition, a.Weapon.Range)
? ab.info.OutsideRangeCursor
: ab.info.Cursor;
? ab.Info.OutsideRangeCursor
: ab.Info.Cursor;
if (target.Type == TargetType.Actor && target.Actor == self)
return false;
@@ -210,7 +228,7 @@ namespace OpenRA.Mods.RA
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
cursor = ab.info.Cursor;
cursor = ab.Info.Cursor;
if (negativeDamage)
return false;
@@ -223,7 +241,7 @@ namespace OpenRA.Mods.RA
var maxRange = ab.GetMaximumRange().Range;
var targetRange = (self.World.Map.CenterOfCell(location) - self.CenterPosition).HorizontalLengthSquared;
if (targetRange > maxRange * maxRange)
cursor = ab.info.OutsideRangeCursor;
cursor = ab.Info.OutsideRangeCursor;
return true;
}

View File

@@ -15,25 +15,48 @@ namespace OpenRA.Mods.RA
{
[Desc("Will AttackMove to a random location within MoveRadius when idle.",
"This conflicts with player orders and should only be added to animal creeps.")]
class AttackWanderInfo : ITraitInfo
class AttackWanderInfo : ITraitInfo, Requires<AttackMoveInfo>
{
public readonly int MoveRadius = 4;
public readonly int WanderMoveRadius = 10;
[Desc("Number of ticks to wait until decreasing the effective move radius.")]
public readonly int MoveReductionRadiusScale = 5;
public object Create(ActorInitializer init) { return new AttackWander(init.self, this); }
}
class AttackWander : INotifyIdle
{
int ticksIdle;
int effectiveMoveRadius;
readonly AttackMove attackMove;
readonly AttackWanderInfo Info;
public AttackWander(Actor self, AttackWanderInfo info)
{
Info = info;
effectiveMoveRadius = info.WanderMoveRadius;
attackMove = self.TraitOrDefault<AttackMove>();
}
public void TickIdle(Actor self)
{
var target = self.CenterPosition + new WVec(0, -1024*Info.MoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255)));
self.Trait<AttackMove>().ResolveOrder(self, new Order("AttackMove", self, false) { TargetLocation = self.World.Map.CellContaining(target) });
var target = self.CenterPosition + new WVec(0, -1024 * effectiveMoveRadius, 0).Rotate(WRot.FromFacing(self.World.SharedRandom.Next(255)));
var targetCell = self.World.Map.CellContaining(target);
if (!self.World.Map.Contains(targetCell))
{
// If MoveRadius is too big there might not be a valid cell to order the attack to (if actor is on a small island and can't leave)
if (++ticksIdle % Info.MoveReductionRadiusScale == 0)
effectiveMoveRadius--;
return; // We'll be back the next tick; better to sit idle for a few seconds than prolongue this tick indefinitely with a loop
}
attackMove.ResolveOrder(self, new Order("AttackMove", self, false) { TargetLocation = targetCell });
ticksIdle = 0;
effectiveMoveRadius = Info.WanderMoveRadius;
}
}
}

View File

@@ -49,7 +49,8 @@ namespace OpenRA.Mods.RA.Traits
public void TickIdle(Actor self)
{
if (TargetLocation.HasValue)
// This might cause the actor to be stuck if the target location is unreachable
if (TargetLocation.HasValue && self.Location != TargetLocation.Value)
Activate(self);
}