Merge pull request #3545 from pchote/infantry-range-fix
Infantry range fix
This commit is contained in:
@@ -79,7 +79,7 @@ namespace OpenRA
|
||||
|
||||
public static void SetListenerPosition(float2 position) { soundEngine.SetListenerPosition(position); }
|
||||
|
||||
static ISound Play(Player player, string name, bool headRelative, PPos pos, float volumeModifier)
|
||||
static ISound Play(Player player, string name, bool headRelative, WPos pos, float volumeModifier)
|
||||
{
|
||||
if (String.IsNullOrEmpty(name))
|
||||
return null;
|
||||
@@ -87,16 +87,16 @@ namespace OpenRA
|
||||
return null;
|
||||
|
||||
return soundEngine.Play2D(sounds[name],
|
||||
false, headRelative, pos.ToFloat2(),
|
||||
false, headRelative, PPos.FromWPosHackZ(pos).ToFloat2(),
|
||||
InternalSoundVolume * volumeModifier, true);
|
||||
}
|
||||
|
||||
public static ISound Play(string name) { return Play(null, name, true, PPos.Zero, 1); }
|
||||
public static ISound Play(string name, PPos pos) { return Play(null, name, false, pos, 1); }
|
||||
public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, PPos.Zero, volumeModifier); }
|
||||
public static ISound Play(string name, PPos pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); }
|
||||
public static ISound PlayToPlayer(Player player, string name) { return Play(player, name, true, PPos.Zero, 1); }
|
||||
public static ISound PlayToPlayer(Player player, string name, PPos pos) { return Play(player, name, false, pos, 1); }
|
||||
public static ISound Play(string name) { return Play(null, name, true, WPos.Zero, 1); }
|
||||
public static ISound Play(string name, WPos pos) { return Play(null, name, false, pos, 1); }
|
||||
public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, WPos.Zero, volumeModifier); }
|
||||
public static ISound Play(string name, WPos pos, float volumeModifier) { return Play(null, name, false, pos, volumeModifier); }
|
||||
public static ISound PlayToPlayer(Player player, string name) { return Play(player, name, true, WPos.Zero, 1); }
|
||||
public static ISound PlayToPlayer(Player player, string name, WPos pos) { return Play(player, name, false, pos, 1); }
|
||||
|
||||
public static void PlayVideo(byte[] raw)
|
||||
{
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace OpenRA.Traits
|
||||
if (targetable == null)
|
||||
return new []{actor.CenterPosition};
|
||||
|
||||
return targetable.TargetableCells(actor).Select(c => c.CenterPosition);
|
||||
return targetable.TargetablePositions(actor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace OpenRA.Traits
|
||||
public interface ITargetable
|
||||
{
|
||||
string[] TargetTypes { get; }
|
||||
IEnumerable<CPos> TargetableCells(Actor self);
|
||||
IEnumerable<WPos> TargetablePositions(Actor self);
|
||||
bool TargetableBy(Actor self, Actor byActor);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace OpenRA.Mods.Cnc
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
Sound.Play(Info.LaunchSound, order.TargetLocation.ToPPos());
|
||||
Sound.Play(Info.LaunchSound, order.TargetLocation.CenterPosition);
|
||||
w.Add(new IonCannon(self, w, order.TargetLocation));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -226,18 +226,18 @@ namespace OpenRA.Mods.RA.AI
|
||||
|
||||
protected static bool CanAttackTarget(Actor a, Actor target)
|
||||
{
|
||||
if (!a.HasTrait<AttackBase>()) return false;
|
||||
if (!target.HasTrait<TargetableUnit<TargetableUnitInfo>>() &&
|
||||
!target.HasTrait<TargetableBuilding>()) return false;
|
||||
if (!a.HasTrait<AttackBase>())
|
||||
return false;
|
||||
|
||||
var targetable = target.TraitOrDefault<ITargetable>();
|
||||
if (targetable == null)
|
||||
return false;
|
||||
|
||||
var arms = a.TraitsImplementing<Armament>();
|
||||
foreach (var arm in arms)
|
||||
if (target.HasTrait<TargetableUnit<TargetableUnitInfo>>() &&
|
||||
arm.Weapon.ValidTargets.Intersect(target.Trait<TargetableUnit<TargetableUnitInfo>>().TargetTypes) != null)
|
||||
return true;
|
||||
else if (target.HasTrait<TargetableBuilding>() &&
|
||||
arm.Weapon.ValidTargets.Intersect(target.Trait<TargetableBuilding>().TargetTypes) != null)
|
||||
if (arm.Weapon.ValidTargets.Intersect(targetable.TargetTypes) != null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread,
|
||||
delayBetweenPathingAttempts + delaySpread);
|
||||
|
||||
return (AllowMovement) ? Util.SequenceActivities(self.Trait<Mobile>().MoveWithinRange(Target, Range.Range / 1024), this) : NextActivity;
|
||||
return (AllowMovement) ? Util.SequenceActivities(self.Trait<Mobile>().MoveWithinRange(Target, Range), this) : NextActivity;
|
||||
}
|
||||
|
||||
var desiredFacing = Util.GetFacing(Target.CenterPosition - self.CenterPosition, 0);
|
||||
|
||||
@@ -15,34 +15,32 @@ namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
public class Follow : Activity
|
||||
{
|
||||
Target Target;
|
||||
int Range;
|
||||
Target target;
|
||||
WRange range;
|
||||
int nextPathTime;
|
||||
|
||||
const int delayBetweenPathingAttempts = 20;
|
||||
const int delaySpread = 5;
|
||||
|
||||
public Follow(Target target, int range)
|
||||
public Follow(Target target, WRange range)
|
||||
{
|
||||
Target = target;
|
||||
Range = range;
|
||||
this.target = target;
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
if (IsCanceled) return NextActivity;
|
||||
if (!Target.IsValid) return NextActivity;
|
||||
if (IsCanceled || !target.IsValid)
|
||||
return NextActivity;
|
||||
|
||||
var inRange = ( Target.CenterPosition.ToCPos() - self.Location ).LengthSquared < Range * Range;
|
||||
|
||||
if( inRange ) return this;
|
||||
if (--nextPathTime > 0) return this;
|
||||
if (target.IsInRange(self.CenterPosition, range) || --nextPathTime > 0)
|
||||
return this;
|
||||
|
||||
nextPathTime = self.World.SharedRandom.Next(delayBetweenPathingAttempts - delaySpread,
|
||||
delayBetweenPathingAttempts + delaySpread);
|
||||
|
||||
var mobile = self.Trait<Mobile>();
|
||||
return Util.SequenceActivities( mobile.MoveWithinRange( Target, Range ), this );
|
||||
return Util.SequenceActivities(mobile.MoveWithinRange(target, range), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
self.Trait<RenderInfantry>().Attacking(self, Target.FromActor(target));
|
||||
|
||||
if (weapon.Report != null && weapon.Report.Any())
|
||||
Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterLocation);
|
||||
Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
|
||||
}
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
var bi = self.Info.Traits.GetOrDefault<BuildingInfo>();
|
||||
if (bi != null)
|
||||
foreach (var s in bi.SellSounds)
|
||||
Sound.PlayToPlayer(self.Owner, s, self.CenterLocation);
|
||||
Sound.PlayToPlayer(self.Owner, s, self.CenterPosition);
|
||||
|
||||
rb.PlayCustomAnimBackwards(self, "make", () => { OnComplete(); complete = true;});
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace OpenRA.Mods.RA.Activities
|
||||
|
||||
public override Activity Tick(Actor self)
|
||||
{
|
||||
Sound.Play("chrono2.aud", self.Location.ToPPos());
|
||||
Sound.Play("chrono2.aud", destination.ToPPos());
|
||||
Sound.Play("chrono2.aud", self.CenterPosition);
|
||||
Sound.Play("chrono2.aud", destination.CenterPosition);
|
||||
|
||||
self.Trait<ITeleportable>().SetPosition(self, destination);
|
||||
self.Generation++;
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Activities
|
||||
|
||||
self.Destroy();
|
||||
foreach (var s in Sounds)
|
||||
Sound.PlayToPlayer(self.Owner, s, self.CenterLocation);
|
||||
Sound.PlayToPlayer(self.Owner, s, self.CenterPosition);
|
||||
|
||||
var init = new TypeDictionary
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA
|
||||
&& self.Owner.WinState != WinState.Lost)
|
||||
{
|
||||
self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, self.CenterPosition)));
|
||||
Sound.Play(info.ChuteSound, self.CenterLocation);
|
||||
Sound.Play(info.ChuteSound, self.CenterPosition);
|
||||
}
|
||||
else
|
||||
pilot.Destroy();
|
||||
|
||||
@@ -21,12 +21,15 @@ namespace OpenRA.Mods.RA.Air
|
||||
public override object Create(ActorInitializer init) { return new TargetableAircraft(init.self, this); }
|
||||
}
|
||||
|
||||
public class TargetableAircraft : TargetableUnit<TargetableAircraftInfo>
|
||||
public class TargetableAircraft : TargetableUnit
|
||||
{
|
||||
Aircraft Aircraft;
|
||||
readonly TargetableAircraftInfo info;
|
||||
readonly Aircraft Aircraft;
|
||||
|
||||
public TargetableAircraft(Actor self, TargetableAircraftInfo info)
|
||||
: base(self, info)
|
||||
{
|
||||
this.info = info;
|
||||
Aircraft = self.Trait<Aircraft>();
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace OpenRA.Mods.RA
|
||||
self.World.Add(projectile);
|
||||
|
||||
if (args.weapon.Report != null && args.weapon.Report.Any())
|
||||
Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterLocation);
|
||||
Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -25,8 +25,12 @@ namespace OpenRA.Mods.RA
|
||||
public class AttackFrontal : AttackBase
|
||||
{
|
||||
readonly AttackFrontalInfo info;
|
||||
|
||||
public AttackFrontal(Actor self, AttackFrontalInfo info)
|
||||
: base( self ) { this.info = info; }
|
||||
: base(self)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
protected override bool CanAttack(Actor self, Target target)
|
||||
{
|
||||
|
||||
@@ -95,12 +95,11 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (weapon != null)
|
||||
{
|
||||
attack.target = target;
|
||||
var range = WRange.FromCells(Math.Max(0, (int)weapon.Weapon.Range - RangeTolerance));
|
||||
|
||||
attack.target = target;
|
||||
if (allowMove && self.HasTrait<Mobile>() && !self.Info.Traits.Get<MobileInfo>().OnRails)
|
||||
return Util.SequenceActivities(
|
||||
new Follow( target, Math.Max( 0, (int)weapon.Weapon.Range - RangeTolerance ) ),
|
||||
this );
|
||||
return Util.SequenceActivities(new Follow(target, range), this);
|
||||
}
|
||||
|
||||
return NextActivity;
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
public void DamageStateChanged(Actor self, AttackInfo e)
|
||||
{
|
||||
if (e.DamageState == DamageState.Dead)
|
||||
Sound.Play(Info.DestroyedSound, self.CenterLocation);
|
||||
Sound.Play(Info.DestroyedSound, self.CenterPosition);
|
||||
else if (e.DamageState >= DamageState.Heavy && e.PreviousDamageState < DamageState.Heavy)
|
||||
Sound.Play(Info.DamagedSound, self.CenterLocation);
|
||||
Sound.Play(Info.DamagedSound, self.CenterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
public void OnCrush(Actor crusher)
|
||||
{
|
||||
self.Kill(crusher);
|
||||
Sound.Play(info.CrushSound, self.CenterLocation);
|
||||
Sound.Play(info.CrushSound, self.CenterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace OpenRA.Mods.RA
|
||||
self.World.Add(args.weapon.Projectile.Create(args));
|
||||
|
||||
if (args.weapon.Report != null && args.weapon.Report.Any())
|
||||
Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterLocation);
|
||||
Sound.Play(args.weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA
|
||||
public void Uncloak(int time)
|
||||
{
|
||||
if (Cloaked)
|
||||
Sound.Play(info.UncloakSound, self.CenterLocation);
|
||||
Sound.Play(info.UncloakSound, self.CenterPosition);
|
||||
|
||||
remainingTime = Math.Max(remainingTime, time);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
if (remainingTime > 0 && canCloak)
|
||||
if (--remainingTime <= 0)
|
||||
Sound.Play(info.CloakSound, self.CenterLocation);
|
||||
Sound.Play(info.CloakSound, self.CenterPosition);
|
||||
if (self.IsDisabled())
|
||||
Uncloak();
|
||||
|
||||
|
||||
@@ -43,11 +43,12 @@ namespace OpenRA.Mods.RA
|
||||
var isWater = args.destAltitude == 0 && world.GetTerrainInfo(targetTile).IsWater;
|
||||
var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion;
|
||||
|
||||
var dest = args.dest.ToWPos(args.destAltitude);
|
||||
if (explosionType != null)
|
||||
world.AddFrameEndTask(
|
||||
w => w.Add(new Explosion(w, args.dest.ToWPos(args.destAltitude), explosionType)));
|
||||
w => w.Add(new Explosion(w, dest, explosionType)));
|
||||
|
||||
Sound.Play(GetImpactSound(warhead, isWater), args.dest);
|
||||
Sound.Play(GetImpactSound(warhead, isWater), dest);
|
||||
|
||||
var smudgeLayers = world.WorldActor.TraitsImplementing<SmudgeLayer>().ToDictionary(x => x.Info.Type);
|
||||
|
||||
@@ -156,7 +157,7 @@ namespace OpenRA.Mods.RA
|
||||
};
|
||||
|
||||
if (args.weapon.Report != null && args.weapon.Report.Any())
|
||||
Sound.Play(args.weapon.Report.Random(attacker.World.SharedRandom), pxPos);
|
||||
Sound.Play(args.weapon.Report.Random(attacker.World.SharedRandom), pos);
|
||||
|
||||
DoImpacts(args);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA.Crates
|
||||
w.Remove(collector);
|
||||
|
||||
collector.AddTrait(cloak);
|
||||
var t = collector.TraitOrDefault<TargetableUnit<TargetableUnitInfo>>();
|
||||
var t = collector.TraitOrDefault<TargetableUnit>();
|
||||
if (t != null) t.ReceivedCloak(collector);
|
||||
|
||||
w.Add(collector);
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public void OnCrush(Actor crusher)
|
||||
{
|
||||
Sound.Play(Info.CrushSound, crusher.CenterLocation);
|
||||
Sound.Play(Info.CrushSound, crusher.CenterPosition);
|
||||
ri.SpawnCorpse(self, Info.CorpseSequence);
|
||||
self.Kill(crusher);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,10 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
var target = Target.FromActor(order.TargetActor);
|
||||
self.SetTargetLine(target, Color.Yellow);
|
||||
|
||||
var range = WRange.FromCells(target.Actor.Info.Traits.Get<GuardableInfo>().Range);
|
||||
self.QueueActivity(false, new AttackMove.AttackMoveActivity(self,
|
||||
new Follow(target, target.Actor.Info.Traits.Get<GuardableInfo>().Range)));
|
||||
new Follow(target, range)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,14 +191,14 @@ namespace OpenRA.Mods.RA.Missions
|
||||
if (einstein != null)
|
||||
{
|
||||
if (einstein.IsInWorld)
|
||||
innerActivity = new Move.Move(Target.FromActor(einstein), 3);
|
||||
innerActivity = new Move.Move(Target.FromActor(einstein), WRange.FromCells(3));
|
||||
|
||||
else
|
||||
{
|
||||
var container = world.UnitContaining(einstein);
|
||||
|
||||
if (container != null && !container.HasTrait<Aircraft>() && container.HasTrait<Mobile>())
|
||||
innerActivity = new Move.Move(Target.FromActor(container), 3);
|
||||
innerActivity = new Move.Move(Target.FromActor(container), WRange.FromCells(3));
|
||||
|
||||
else
|
||||
innerActivity = new Move.Move(extractionLZ.Location, 3);
|
||||
|
||||
@@ -516,7 +516,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
public Activity ScriptedMove(CPos cell) { return new Move(cell); }
|
||||
public Activity MoveTo(CPos cell, int nearEnough) { return new Move(cell, nearEnough); }
|
||||
public Activity MoveTo(CPos cell, Actor ignoredActor) { return new Move(cell, ignoredActor); }
|
||||
public Activity MoveWithinRange(Target target, int range) { return new Move(target, range); }
|
||||
public Activity MoveWithinRange(Target target, WRange range) { return new Move(target, range); }
|
||||
public Activity MoveTo(Func<List<CPos>> pathFunc) { return new Move(pathFunc); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,16 @@ namespace OpenRA.Mods.RA.Move
|
||||
class Move : Activity
|
||||
{
|
||||
CPos? destination;
|
||||
int nearEnough;
|
||||
WRange nearEnough;
|
||||
public List<CPos> path;
|
||||
Func<Actor, Mobile, List<CPos>> getPath;
|
||||
public Actor ignoreBuilding;
|
||||
|
||||
// For dealing with blockers
|
||||
bool hasWaited;
|
||||
bool hasNotifiedBlocker;
|
||||
int waitTicksRemaining;
|
||||
|
||||
// Scriptable move order
|
||||
// Ignores lane bias and nearby units
|
||||
public Move(CPos destination)
|
||||
@@ -35,10 +40,14 @@ namespace OpenRA.Mods.RA.Move
|
||||
PathSearch.FromPoint( self.World, mobile.Info, self, mobile.toCell, destination, false )
|
||||
.WithoutLaneBias());
|
||||
this.destination = destination;
|
||||
this.nearEnough = 0;
|
||||
this.nearEnough = WRange.Zero;
|
||||
}
|
||||
|
||||
// Hack for legacy code
|
||||
public Move(CPos destination, int nearEnough)
|
||||
: this(destination, WRange.FromCells(nearEnough)) {}
|
||||
|
||||
public Move(CPos destination, WRange nearEnough)
|
||||
{
|
||||
this.getPath = (self,mobile) => self.World.WorldActor.Trait<PathFinder>().FindUnitPath( mobile.toCell, destination, self );
|
||||
this.destination = destination;
|
||||
@@ -54,12 +63,12 @@ namespace OpenRA.Mods.RA.Move
|
||||
);
|
||||
|
||||
this.destination = destination;
|
||||
this.nearEnough = 0;
|
||||
this.nearEnough = WRange.Zero;
|
||||
this.ignoreBuilding = ignoreBuilding;
|
||||
}
|
||||
|
||||
static readonly List<CPos> NoPath = new List<CPos>();
|
||||
public Move(Target target, int range)
|
||||
public Move(Target target, WRange range)
|
||||
{
|
||||
this.getPath = (self, mobile) =>
|
||||
{
|
||||
@@ -67,7 +76,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
return NoPath;
|
||||
|
||||
return self.World.WorldActor.Trait<PathFinder>().FindUnitPathToRange(
|
||||
mobile.toCell, target.CenterPosition.ToCPos(), range, self);
|
||||
mobile.toCell, mobile.toSubCell, target.CenterPosition, range, self);
|
||||
};
|
||||
|
||||
this.destination = null;
|
||||
@@ -78,7 +87,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
this.getPath = (_1,_2) => getPath();
|
||||
this.destination = null;
|
||||
this.nearEnough = 0;
|
||||
this.nearEnough = WRange.Zero;
|
||||
}
|
||||
|
||||
static int HashList<T>(List<T> xs)
|
||||
@@ -95,8 +104,6 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
var path = getPath(self, mobile).TakeWhile(a => a != mobile.toCell).ToList();
|
||||
mobile.PathHash = HashList(path);
|
||||
Log.Write("debug", "EvalPathHash #{0} {1}",
|
||||
self.ActorID, mobile.PathHash);
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -109,6 +116,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
if (mobile.Altitude < info.Altitude)
|
||||
++mobile.Altitude;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -155,7 +163,8 @@ namespace OpenRA.Mods.RA.Move
|
||||
Util.BetweenCells(mobile.fromCell, mobile.toCell) + (MobileInfo.SubCellOffsets[mobile.fromSubCell] + MobileInfo.SubCellOffsets[mobile.toSubCell]) / 2,
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
0 );
|
||||
0
|
||||
);
|
||||
|
||||
return move;
|
||||
}
|
||||
@@ -171,10 +180,6 @@ namespace OpenRA.Mods.RA.Move
|
||||
throw new InvalidOperationException("(Move) Sanity check failed");
|
||||
}
|
||||
|
||||
bool hasWaited;
|
||||
bool hasNotifiedBlocker;
|
||||
int waitTicksRemaining;
|
||||
|
||||
void NotifyBlocker(Actor self, CPos nextCell)
|
||||
{
|
||||
foreach (var blocker in self.World.ActorMap.GetUnitsAt(nextCell))
|
||||
@@ -191,22 +196,30 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
Pair<CPos, SubCell>? PopPath(Actor self, Mobile mobile)
|
||||
{
|
||||
if( path.Count == 0 ) return null;
|
||||
if (path.Count == 0)
|
||||
return null;
|
||||
|
||||
var nextCell = path[path.Count - 1];
|
||||
|
||||
// Next cell in the move is blocked by another actor
|
||||
if (!mobile.CanEnterCell(nextCell, ignoreBuilding, true))
|
||||
{
|
||||
if( ( mobile.toCell - destination.Value ).LengthSquared <= nearEnough )
|
||||
// Are we close enough?
|
||||
var cellRange = nearEnough.Range / 1024;
|
||||
if ((mobile.toCell - destination.Value).LengthSquared <= cellRange*cellRange)
|
||||
{
|
||||
path.Clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
// See if they will move
|
||||
if (!hasNotifiedBlocker)
|
||||
{
|
||||
NotifyBlocker(self, nextCell);
|
||||
hasNotifiedBlocker = true;
|
||||
}
|
||||
|
||||
// Wait a bit to see if they leave
|
||||
if (!hasWaited)
|
||||
{
|
||||
var info = self.Info.Traits.Get<MobileInfo>();
|
||||
@@ -223,6 +236,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculate a new path
|
||||
mobile.RemoveInfluence();
|
||||
var newPath = EvalPath(self, mobile);
|
||||
mobile.AddInfluence();
|
||||
@@ -232,6 +246,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
hasNotifiedBlocker = false;
|
||||
hasWaited = false;
|
||||
path.RemoveAt(path.Count - 1);
|
||||
@@ -271,7 +286,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
this.fromFacing = fromFacing;
|
||||
this.toFacing = toFacing;
|
||||
this.moveFraction = startingFraction;
|
||||
this.moveFractionTotal = ( ( to - from ) * 3 ).Length;
|
||||
this.moveFractionTotal = 3*(to - from).Length;
|
||||
}
|
||||
|
||||
public override void Cancel(Actor self)
|
||||
@@ -357,7 +372,8 @@ namespace OpenRA.Mods.RA.Move
|
||||
Util.BetweenCells(mobile.toCell, nextCell.Value.First) + (toSubcellOffset + nextSubcellOffset) / 2,
|
||||
mobile.Facing,
|
||||
Util.GetNearestFacing(mobile.Facing, Util.GetFacing(nextCell.Value.First - mobile.toCell, mobile.Facing)),
|
||||
moveFraction - moveFractionTotal );
|
||||
moveFraction - moveFractionTotal
|
||||
);
|
||||
|
||||
mobile.SetLocation(mobile.toCell, mobile.toSubCell, nextCell.Value.First, nextCell.Value.Second);
|
||||
return ret;
|
||||
@@ -372,7 +388,8 @@ namespace OpenRA.Mods.RA.Move
|
||||
Util.CenterOfCell(mobile.toCell) + toSubcellOffset,
|
||||
mobile.Facing,
|
||||
mobile.Facing,
|
||||
moveFraction - moveFractionTotal );
|
||||
moveFraction - moveFractionTotal
|
||||
);
|
||||
|
||||
mobile.EnteringCell(self);
|
||||
mobile.SetLocation(mobile.toCell, mobile.toSubCell, mobile.toCell, mobile.toSubCell);
|
||||
@@ -383,9 +400,7 @@ namespace OpenRA.Mods.RA.Move
|
||||
class MoveSecondHalf : MovePart
|
||||
{
|
||||
public MoveSecondHalf(Move move, PPos from, PPos to, int fromFacing, int toFacing, int startingFraction)
|
||||
: base( move, from, to, fromFacing, toFacing, startingFraction )
|
||||
{
|
||||
}
|
||||
: base(move, from, to, fromFacing, toFacing, startingFraction) {}
|
||||
|
||||
protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent)
|
||||
{
|
||||
@@ -401,7 +416,8 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
public static bool IsMoving(this Actor self)
|
||||
{
|
||||
if (self.IsIdle) return false;
|
||||
if (self.IsIdle)
|
||||
return false;
|
||||
|
||||
Activity a = self.GetCurrentActivity();
|
||||
Debug.Assert(a != null);
|
||||
|
||||
@@ -68,17 +68,27 @@ namespace OpenRA.Mods.RA.Move
|
||||
}
|
||||
}
|
||||
|
||||
public List<CPos> FindUnitPathToRange(CPos src, CPos target, int range, Actor self)
|
||||
public List<CPos> FindUnitPathToRange(CPos src, SubCell srcSub, WPos target, WRange range, Actor self)
|
||||
{
|
||||
using (new PerfSample("Pathfinder"))
|
||||
{
|
||||
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||
var tilesInRange = world.FindTilesInCircle(target, range)
|
||||
.Where(t => mi.CanEnterCell(self.World, self, t, null, true, true));
|
||||
var targetCell = target.ToCPos();
|
||||
var rangeSquared = range.Range*range.Range;
|
||||
|
||||
// Correct for SubCell offset
|
||||
var so = MobileInfo.SubCellOffsets[srcSub];
|
||||
target -= new WVec(so.X * 1024 / Game.CellSize, so.Y * 1024 / Game.CellSize, 0);
|
||||
|
||||
// Select only the tiles that are within range from the requested SubCell
|
||||
// This assumes that the SubCell does not change during the path traversal
|
||||
var tilesInRange = world.FindTilesInCircle(targetCell, range.Range / 1024 + 1)
|
||||
.Where(t => (t.CenterPosition - target).LengthSquared <= rangeSquared
|
||||
&& mi.CanEnterCell(self.World, self, t, null, true, true));
|
||||
|
||||
var path = FindBidiPath(
|
||||
PathSearch.FromPoints(world, mi, self, tilesInRange, src, true),
|
||||
PathSearch.FromPoint(world, mi, self, src, target, true).InReverse()
|
||||
PathSearch.FromPoint(world, mi, self, src, targetCell, true).InReverse()
|
||||
);
|
||||
|
||||
return path;
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
var a = cargo.Unload(self);
|
||||
self.World.AddFrameEndTask(w => w.Add(new Parachute(a, self.CenterPosition)));
|
||||
Sound.Play(info.ChuteSound, self.CenterLocation);
|
||||
Sound.Play(info.ChuteSound, self.CenterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (playSounds)
|
||||
foreach (var s in buildingInfo.BuildSounds)
|
||||
Sound.PlayToPlayer(order.Player, s, building.CenterLocation);
|
||||
Sound.PlayToPlayer(order.Player, s, building.CenterPosition);
|
||||
playSounds = false;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ namespace OpenRA.Mods.RA
|
||||
new OwnerInit( order.Player ),
|
||||
});
|
||||
foreach (var s in buildingInfo.BuildSounds)
|
||||
Sound.PlayToPlayer(order.Player, s, building.CenterLocation);
|
||||
Sound.PlayToPlayer(order.Player, s, building.CenterPosition);
|
||||
}
|
||||
|
||||
PlayBuildAnim( self, unit );
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA.Render
|
||||
|
||||
public void PlayCharge(Actor self)
|
||||
{
|
||||
Sound.Play(info.ChargeAudio, self.CenterLocation);
|
||||
Sound.Play(info.ChargeAudio, self.CenterPosition);
|
||||
anim.PlayThen(NormalizeSequence(self, "active"),
|
||||
() => anim.PlayRepeating(NormalizeSequence(self, "idle")));
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace OpenRA.Mods.RA
|
||||
var target = Target.FromOrder(order);
|
||||
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(mobile.MoveWithinRange(target, info.CloseEnough));
|
||||
self.QueueActivity(mobile.MoveWithinRange(target, new WRange(1024*info.CloseEnough)));
|
||||
self.QueueActivity(new Repair(order.TargetActor));
|
||||
|
||||
self.SetTargetLine(target, Color.Green, false);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
self.Trait<RenderBuilding>().PlayCustomAnim(self, "active");
|
||||
|
||||
Sound.Play("ironcur9.aud", order.TargetLocation.ToPPos());
|
||||
Sound.Play("ironcur9.aud", order.TargetLocation.CenterPosition);
|
||||
|
||||
foreach (var target in UnitsInRange(order.TargetLocation)
|
||||
.Where(a => a.Owner.Stances[self.Owner] == Stance.Ally))
|
||||
|
||||
@@ -15,25 +15,30 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class TargetableBuildingInfo : ITraitInfo, Requires<BuildingInfo>
|
||||
public class TargetableBuildingInfo : ITraitInfo, Requires<BuildingInfo>
|
||||
{
|
||||
public readonly string[] TargetTypes = { };
|
||||
|
||||
public object Create( ActorInitializer init ) { return new TargetableBuilding( this ); }
|
||||
public object Create(ActorInitializer init) { return new TargetableBuilding(init.self, this); }
|
||||
}
|
||||
|
||||
class TargetableBuilding : ITargetable
|
||||
public class TargetableBuilding : ITargetable
|
||||
{
|
||||
readonly TargetableBuildingInfo info;
|
||||
readonly Building building;
|
||||
|
||||
public TargetableBuilding( TargetableBuildingInfo info ) { this.info = info; }
|
||||
public TargetableBuilding(Actor self, TargetableBuildingInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
building = self.Trait<Building>();
|
||||
}
|
||||
|
||||
public string[] TargetTypes { get { return info.TargetTypes; } }
|
||||
public bool TargetableBy(Actor self, Actor byActor) { return true; }
|
||||
|
||||
public IEnumerable<CPos> TargetableCells( Actor self )
|
||||
public IEnumerable<WPos> TargetablePositions(Actor self)
|
||||
{
|
||||
return self.Trait<Building>().OccupiedCells().Select(c => c.First);
|
||||
return building.OccupiedCells().Select(c => c.First.CenterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,19 @@ namespace OpenRA.Mods.RA
|
||||
public override object Create(ActorInitializer init) { return new TargetableSubmarine(init.self, this); }
|
||||
}
|
||||
|
||||
public class TargetableSubmarine : TargetableUnit<TargetableSubmarineInfo>
|
||||
public class TargetableSubmarine : TargetableUnit
|
||||
{
|
||||
readonly TargetableSubmarineInfo info;
|
||||
|
||||
public TargetableSubmarine(Actor self, TargetableSubmarineInfo info)
|
||||
: base(self, info) {}
|
||||
: base(self, info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public override string[] TargetTypes
|
||||
{
|
||||
get { return Cloak.Cloaked ? info.CloakedTargetTypes
|
||||
get { return cloak.Cloaked ? info.CloakedTargetTypes
|
||||
: info.TargetTypes;}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,15 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
public readonly string[] TargetTypes = { };
|
||||
|
||||
public virtual object Create( ActorInitializer init ) { return new TargetableUnit<TargetableUnitInfo>( init.self, this ); }
|
||||
public virtual object Create(ActorInitializer init) { return new TargetableUnit(init.self, this); }
|
||||
}
|
||||
|
||||
public class TargetableUnit<Info> : ITargetable
|
||||
where Info : TargetableUnitInfo
|
||||
public class TargetableUnit : ITargetable
|
||||
{
|
||||
protected readonly Info info;
|
||||
protected Cloak Cloak;
|
||||
readonly TargetableUnitInfo info;
|
||||
protected Cloak cloak;
|
||||
|
||||
public TargetableUnit( Actor self, Info info )
|
||||
public TargetableUnit(Actor self, TargetableUnitInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
ReceivedCloak(self);
|
||||
@@ -36,15 +35,15 @@ namespace OpenRA.Mods.RA
|
||||
// Arbitrary units can receive cloak via a crate during gameplay
|
||||
public void ReceivedCloak(Actor self)
|
||||
{
|
||||
Cloak = self.TraitOrDefault<Cloak>();
|
||||
cloak = self.TraitOrDefault<Cloak>();
|
||||
}
|
||||
|
||||
public virtual bool TargetableBy(Actor self, Actor byActor)
|
||||
{
|
||||
if (Cloak == null)
|
||||
if (cloak == null || !cloak.Cloaked)
|
||||
return true;
|
||||
|
||||
if (!Cloak.Cloaked || self.Owner == byActor.Owner || self.Owner.Stances[byActor.Owner] == Stance.Ally)
|
||||
if (self.Owner.IsAlliedWith(byActor.Owner))
|
||||
return true;
|
||||
|
||||
return self.World.ActorsWithTrait<DetectCloaked>().Any(a => (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get<DetectCloakedInfo>().Range);
|
||||
@@ -52,9 +51,9 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public virtual string[] TargetTypes { get { return info.TargetTypes; } }
|
||||
|
||||
public virtual IEnumerable<CPos> TargetableCells( Actor self )
|
||||
public virtual IEnumerable<WPos> TargetablePositions(Actor self)
|
||||
{
|
||||
yield return self.CenterPosition.ToCPos();
|
||||
yield return self.CenterPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user