Remove AmmoPool-awareness from Armament

This commit is contained in:
reaperrr
2017-10-15 18:28:33 +02:00
committed by Paul Chote
parent ded92f394c
commit 8b7a71685c
7 changed files with 66 additions and 51 deletions

View File

@@ -96,7 +96,7 @@ namespace OpenRA.Mods.Cnc.Activities
var pool = ammoPools.FirstOrDefault(x => x.Info.Name == info.AmmoPoolName); var pool = ammoPools.FirstOrDefault(x => x.Info.Name == info.AmmoPoolName);
if (pool == null) if (pool == null)
return; return;
pool.TakeAmmo(); pool.TakeAmmo(self, 1);
} }
self.World.AddFrameEndTask( self.World.AddFrameEndTask(

View File

@@ -22,6 +22,7 @@ namespace OpenRA.Mods.Common.Activities
readonly Aircraft aircraft; readonly Aircraft aircraft;
readonly AttackPlane attackPlane; readonly AttackPlane attackPlane;
readonly bool selfReloads;
int ticksUntilTurn; int ticksUntilTurn;
public FlyAttack(Actor self, Target target) public FlyAttack(Actor self, Target target)
@@ -30,6 +31,7 @@ namespace OpenRA.Mods.Common.Activities
aircraft = self.Trait<Aircraft>(); aircraft = self.Trait<Aircraft>();
attackPlane = self.TraitOrDefault<AttackPlane>(); attackPlane = self.TraitOrDefault<AttackPlane>();
ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay; ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay;
selfReloads = self.TraitsImplementing<AmmoPool>().All(p => p.SelfReloads);
} }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
@@ -44,8 +46,8 @@ namespace OpenRA.Mods.Common.Activities
if (!target.IsValidFor(self)) if (!target.IsValidFor(self))
return NextActivity; return NextActivity;
// If all valid weapons have depleted their ammo, return to RearmBuilding to reload and then resume the activity // If all valid weapons have depleted their ammo and RearmBuilding is defined, return to RearmBuilding to reload and then resume the activity
if (attackPlane.Armaments.All(x => x.OutOfAmmo || !x.Weapon.IsValidAgainst(target, self.World, self))) if (!selfReloads && aircraft.Info.RearmBuildings.Any() && attackPlane.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self)))
return ActivityUtils.SequenceActivities(new ReturnToBase(self, aircraft.Info.AbortOnResupply), this); return ActivityUtils.SequenceActivities(new ReturnToBase(self, aircraft.Info.AbortOnResupply), this);
if (attackPlane != null) if (attackPlane != null)

View File

@@ -22,6 +22,7 @@ namespace OpenRA.Mods.Common.Activities
readonly Aircraft helicopter; readonly Aircraft helicopter;
readonly AttackHeli attackHeli; readonly AttackHeli attackHeli;
readonly bool attackOnlyVisibleTargets; readonly bool attackOnlyVisibleTargets;
readonly bool selfReloads;
Target target; Target target;
bool canHideUnderFog; bool canHideUnderFog;
@@ -46,6 +47,7 @@ namespace OpenRA.Mods.Common.Activities
helicopter = self.Trait<Aircraft>(); helicopter = self.Trait<Aircraft>();
attackHeli = self.Trait<AttackHeli>(); attackHeli = self.Trait<AttackHeli>();
this.attackOnlyVisibleTargets = attackOnlyVisibleTargets; this.attackOnlyVisibleTargets = attackOnlyVisibleTargets;
selfReloads = self.TraitsImplementing<AmmoPool>().All(p => p.SelfReloads);
} }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
@@ -72,8 +74,8 @@ namespace OpenRA.Mods.Common.Activities
return new HeliFly(self, newTarget); return new HeliFly(self, newTarget);
} }
// If all valid weapons have depleted their ammo, return to RearmBuilding to reload and then resume the activity // If all valid weapons have depleted their ammo and RearmBuilding is defined, return to RearmBuilding to reload and then resume the activity
if (attackHeli.Armaments.All(x => x.OutOfAmmo || !x.Weapon.IsValidAgainst(target, self.World, self))) if (!selfReloads && helicopter.Info.RearmBuildings.Any() && attackHeli.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self)))
return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, helicopter.Info.AbortOnResupply), this); return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, helicopter.Info.AbortOnResupply), this);
var dist = targetPos - pos; var dist = targetPos - pos;

View File

@@ -59,17 +59,9 @@ namespace OpenRA.Mods.Common.Scripting
throw new LuaException("Invalid ammopool name {0} queried on actor {1}.".F(poolName, self)); throw new LuaException("Invalid ammopool name {0} queried on actor {1}.".F(poolName, self));
if (amount > 0) if (amount > 0)
{ pool.GiveAmmo(self, amount);
while (amount-- > 0)
if (!pool.GiveAmmo())
return;
}
else else
{ pool.TakeAmmo(self, -amount);
while (amount++ < 0)
if (!pool.TakeAmmo())
return;
}
} }
} }
} }

View File

@@ -18,9 +18,12 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Actor has a limited amount of ammo, after using it all the actor must reload in some way.")] [Desc("Actor has a limited amount of ammo, after using it all the actor must reload in some way.")]
public class AmmoPoolInfo : ITraitInfo public class AmmoPoolInfo : ITraitInfo
{ {
[Desc("Name of this ammo pool, used to link armaments and reload traits to this pool.")] [Desc("Name of this ammo pool, used to link reload traits to this pool.")]
public readonly string Name = "primary"; public readonly string Name = "primary";
[Desc("Name(s) of armament(s) that use this pool.")]
public readonly string[] Armaments = { "primary", "secondary" };
[Desc("How much ammo does this pool contain when fully loaded.")] [Desc("How much ammo does this pool contain when fully loaded.")]
public readonly int Ammo = 1; public readonly int Ammo = 1;
@@ -46,6 +49,10 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Time to reload per ReloadCount on airfield etc.")] [Desc("Time to reload per ReloadCount on airfield etc.")]
public readonly int ReloadDelay = 50; public readonly int ReloadDelay = 50;
[GrantedConditionReference]
[Desc("The condition to grant to self if the pool has any ammo.")]
public readonly string AmmoCondition = null;
public object Create(ActorInitializer init) { return new AmmoPool(init.Self, this); } public object Create(ActorInitializer init) { return new AmmoPool(init.Self, this); }
} }
@@ -53,7 +60,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
public readonly AmmoPoolInfo Info; public readonly AmmoPoolInfo Info;
ConditionManager conditionManager; ConditionManager conditionManager;
int emptyToken = ConditionManager.InvalidConditionToken; int token = ConditionManager.InvalidConditionToken;
bool selfReloads; bool selfReloads;
@@ -64,31 +71,30 @@ namespace OpenRA.Mods.Common.Traits
public AmmoPool(Actor self, AmmoPoolInfo info) public AmmoPool(Actor self, AmmoPoolInfo info)
{ {
Info = info; Info = info;
if (Info.InitialAmmo < Info.Ammo && Info.InitialAmmo >= 0) currentAmmo = Info.InitialAmmo < Info.Ammo && Info.InitialAmmo >= 0 ? Info.InitialAmmo : Info.Ammo;
currentAmmo = Info.InitialAmmo;
else
currentAmmo = Info.Ammo;
} }
public int GetAmmoCount() { return currentAmmo; } public int GetAmmoCount() { return currentAmmo; }
public bool FullAmmo() { return currentAmmo == Info.Ammo; } public bool FullAmmo() { return currentAmmo == Info.Ammo; }
public bool HasAmmo() { return currentAmmo > 0; } public bool HasAmmo() { return currentAmmo > 0; }
public bool GiveAmmo() public bool GiveAmmo(Actor self, int count)
{ {
if (currentAmmo >= Info.Ammo) if (currentAmmo >= Info.Ammo || count < 0)
return false; return false;
++currentAmmo; currentAmmo = (currentAmmo + count).Clamp(0, Info.Ammo);
UpdateCondition(self);
return true; return true;
} }
public bool TakeAmmo() public bool TakeAmmo(Actor self, int count)
{ {
if (currentAmmo <= 0) if (currentAmmo <= 0 || count < 0)
return false; return false;
--currentAmmo; currentAmmo = (currentAmmo - count).Clamp(0, Info.Ammo);
UpdateCondition(self);
return true; return true;
} }
@@ -100,6 +106,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
conditionManager = self.TraitOrDefault<ConditionManager>(); conditionManager = self.TraitOrDefault<ConditionManager>();
selfReloads = self.TraitsImplementing<ReloadAmmoPool>().Any(r => r.Info.AmmoPool == Info.Name && r.Info.RequiresCondition == null); selfReloads = self.TraitsImplementing<ReloadAmmoPool>().Any(r => r.Info.AmmoPool == Info.Name && r.Info.RequiresCondition == null);
UpdateCondition(self);
// HACK: Temporarily needed until Rearm activity is gone for good // HACK: Temporarily needed until Rearm activity is gone for good
RemainingTicks = Info.ReloadDelay; RemainingTicks = Info.ReloadDelay;
@@ -107,12 +114,24 @@ namespace OpenRA.Mods.Common.Traits
void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel)
{ {
if (a != null && a.Info.AmmoPoolName == Info.Name) if (a != null && Info.Armaments.Contains(a.Info.Name))
TakeAmmo(); TakeAmmo(self, 1);
} }
void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { } void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { }
void UpdateCondition(Actor self)
{
if (conditionManager == null || string.IsNullOrEmpty(Info.AmmoCondition))
return;
if (HasAmmo() && token == ConditionManager.InvalidConditionToken)
token = conditionManager.GrantCondition(self, Info.AmmoCondition);
if (!HasAmmo() && token != ConditionManager.InvalidConditionToken)
token = conditionManager.RevokeCondition(self, token);
}
public IEnumerable<PipType> GetPips(Actor self) public IEnumerable<PipType> GetPips(Actor self)
{ {
var pips = Info.PipCount >= 0 ? Info.PipCount : Info.Ammo; var pips = Info.PipCount >= 0 ? Info.PipCount : Info.Ammo;

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.Common.Traits
} }
[Desc("Allows you to attach weapons to the unit (use @IdentifierSuffix for > 1)")] [Desc("Allows you to attach weapons to the unit (use @IdentifierSuffix for > 1)")]
public class ArmamentInfo : ConditionalTraitInfo, Requires<AttackBaseInfo> public class ArmamentInfo : PausableConditionalTraitInfo, Requires<AttackBaseInfo>
{ {
public readonly string Name = "primary"; public readonly string Name = "primary";
@@ -33,9 +33,6 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Has to be defined in weapons.yaml as well.")] [Desc("Has to be defined in weapons.yaml as well.")]
public readonly string Weapon = null; public readonly string Weapon = null;
[Desc("Which limited ammo pool (if present) should this armament be assigned to.")]
public readonly string AmmoPoolName = "primary";
[Desc("Which turret (if present) should this armament be assigned to.")] [Desc("Which turret (if present) should this armament be assigned to.")]
public readonly string Turret = "primary"; public readonly string Turret = "primary";
@@ -99,15 +96,13 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class Armament : ConditionalTrait<ArmamentInfo>, ITick, IExplodeModifier public class Armament : PausableConditionalTrait<ArmamentInfo>, ITick, IExplodeModifier
{ {
public readonly WeaponInfo Weapon; public readonly WeaponInfo Weapon;
public readonly Barrel[] Barrels; public readonly Barrel[] Barrels;
readonly Actor self; readonly Actor self;
Turreted turret; Turreted turret;
AmmoPool ammoPool;
ReloadAmmoPool reloadAmmoPool;
BodyOrientation coords; BodyOrientation coords;
INotifyBurstComplete[] notifyBurstComplete; INotifyBurstComplete[] notifyBurstComplete;
INotifyAttack[] notifyAttacks; INotifyAttack[] notifyAttacks;
@@ -157,8 +152,6 @@ namespace OpenRA.Mods.Common.Traits
protected override void Created(Actor self) protected override void Created(Actor self)
{ {
turret = self.TraitsImplementing<Turreted>().FirstOrDefault(t => t.Name == Info.Turret); turret = self.TraitsImplementing<Turreted>().FirstOrDefault(t => t.Name == Info.Turret);
ammoPool = self.TraitsImplementing<AmmoPool>().FirstOrDefault(la => la.Info.Name == Info.AmmoPoolName);
reloadAmmoPool = self.TraitsImplementing<ReloadAmmoPool>().FirstOrDefault(ra => ra.Info.AmmoPool == Info.AmmoPoolName);
coords = self.Trait<BodyOrientation>(); coords = self.Trait<BodyOrientation>();
notifyBurstComplete = self.TraitsImplementing<INotifyBurstComplete>().ToArray(); notifyBurstComplete = self.TraitsImplementing<INotifyBurstComplete>().ToArray();
notifyAttacks = self.TraitsImplementing<INotifyAttack>().ToArray(); notifyAttacks = self.TraitsImplementing<INotifyAttack>().ToArray();
@@ -211,7 +204,7 @@ namespace OpenRA.Mods.Common.Traits
protected virtual bool CanFire(Actor self, Target target) protected virtual bool CanFire(Actor self, Target target)
{ {
if (IsReloading || (ammoPool != null && !ammoPool.HasAmmo())) if (IsReloading || IsTraitPaused)
return false; return false;
if (turret != null && !turret.HasAchievedDesiredFacing) if (turret != null && !turret.HasAchievedDesiredFacing)
@@ -341,7 +334,6 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public virtual bool OutOfAmmo { get { return ammoPool != null && !ammoPool.HasAmmo() && (reloadAmmoPool == null || reloadAmmoPool.IsTraitDisabled); } }
public virtual bool IsReloading { get { return FireDelay > 0 || IsTraitDisabled; } } public virtual bool IsReloading { get { return FireDelay > 0 || IsTraitDisabled; } }
public virtual bool AllowExplode { get { return !IsReloading; } } public virtual bool AllowExplode { get { return !IsReloading; } }
bool IExplodeModifier.ShouldExplode(Actor self) { return AllowExplode; } bool IExplodeModifier.ShouldExplode(Actor self) { return AllowExplode; }

View File

@@ -177,7 +177,7 @@ namespace OpenRA.Mods.Common.Traits
// PERF: Avoid LINQ. // PERF: Avoid LINQ.
foreach (var armament in Armaments) foreach (var armament in Armaments)
{ {
var checkIsValid = checkForCenterTargetingWeapons ? armament.Weapon.TargetActorCenter : !armament.OutOfAmmo; var checkIsValid = checkForCenterTargetingWeapons ? armament.Weapon.TargetActorCenter : !armament.IsTraitPaused;
if (checkIsValid && !armament.IsTraitDisabled && armament.Weapon.IsValidAgainst(t, self.World, self)) if (checkIsValid && !armament.IsTraitDisabled && armament.Weapon.IsValidAgainst(t, self.World, self))
return true; return true;
} }
@@ -202,7 +202,7 @@ namespace OpenRA.Mods.Common.Traits
if (armament.IsTraitDisabled) if (armament.IsTraitDisabled)
continue; continue;
if (armament.OutOfAmmo) if (armament.IsTraitPaused)
continue; continue;
var range = armament.Weapon.MinRange; var range = armament.Weapon.MinRange;
@@ -225,7 +225,7 @@ namespace OpenRA.Mods.Common.Traits
if (armament.IsTraitDisabled) if (armament.IsTraitDisabled)
continue; continue;
if (armament.OutOfAmmo) if (armament.IsTraitPaused)
continue; continue;
var range = armament.MaxRange(); var range = armament.MaxRange();
@@ -248,7 +248,7 @@ namespace OpenRA.Mods.Common.Traits
if (armament.IsTraitDisabled) if (armament.IsTraitDisabled)
continue; continue;
if (armament.OutOfAmmo) if (armament.IsTraitPaused)
continue; continue;
if (!armament.Weapon.IsValidAgainst(target, self.World, self)) if (!armament.Weapon.IsValidAgainst(target, self.World, self))
@@ -267,25 +267,33 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled) if (IsTraitDisabled)
return WDist.Zero; return WDist.Zero;
// PERF: Avoid LINQ.
var max = WDist.Zero; var max = WDist.Zero;
// We want actors to use only weapons with ammo for this, except when ALL weapons are out of ammo,
// then we use the paused, valid weapon with highest range.
var maxFallback = WDist.Zero;
// PERF: Avoid LINQ.
foreach (var armament in Armaments) foreach (var armament in Armaments)
{ {
if (armament.IsTraitDisabled) if (armament.IsTraitDisabled)
continue; continue;
if (armament.OutOfAmmo)
continue;
if (!armament.Weapon.IsValidAgainst(target, self.World, self)) if (!armament.Weapon.IsValidAgainst(target, self.World, self))
continue; continue;
var range = armament.MaxRange(); var range = armament.MaxRange();
if (maxFallback < range)
maxFallback = range;
if (armament.IsTraitPaused)
continue;
if (max < range) if (max < range)
max = range; max = range;
} }
return max; return max != WDist.Zero ? max : maxFallback;
} }
// Enumerates all armaments, that this actor possesses, that can be used against Target t // Enumerates all armaments, that this actor possesses, that can be used against Target t
@@ -392,7 +400,7 @@ namespace OpenRA.Mods.Common.Traits
// Use valid armament with highest range out of those that have ammo // Use valid armament with highest range out of those that have ammo
// If all are out of ammo, just use valid armament with highest range // If all are out of ammo, just use valid armament with highest range
armaments = armaments.OrderByDescending(x => x.MaxRange()); armaments = armaments.OrderByDescending(x => x.MaxRange());
var a = armaments.FirstOrDefault(x => !x.OutOfAmmo); var a = armaments.FirstOrDefault(x => !x.IsTraitPaused);
if (a == null) if (a == null)
a = armaments.First(); a = armaments.First();
@@ -426,7 +434,7 @@ namespace OpenRA.Mods.Common.Traits
// Use valid armament with highest range out of those that have ammo // Use valid armament with highest range out of those that have ammo
// If all are out of ammo, just use valid armament with highest range // If all are out of ammo, just use valid armament with highest range
armaments = armaments.OrderByDescending(x => x.MaxRange()); armaments = armaments.OrderByDescending(x => x.MaxRange());
var a = armaments.FirstOrDefault(x => !x.OutOfAmmo); var a = armaments.FirstOrDefault(x => !x.IsTraitPaused);
if (a == null) if (a == null)
a = armaments.First(); a = armaments.First();