Merge pull request #3545 from pchote/infantry-range-fix

Infantry range fix
This commit is contained in:
Matthias Mailänder
2013-07-11 11:45:15 -07:00
36 changed files with 219 additions and 177 deletions

View File

@@ -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)
{

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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));
});
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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)

View File

@@ -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;});
}

View File

@@ -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++;

View File

@@ -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
{

View File

@@ -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();

View File

@@ -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>();
}

View File

@@ -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);
}
});

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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)));
}
}

View File

@@ -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);

View File

@@ -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); }
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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 );

View File

@@ -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")));
}

View File

@@ -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);

View File

@@ -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))

View File

@@ -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);
}
}
}

View File

@@ -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;}
}
}

View File

@@ -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;
}
}
}