Merge pull request #7324 from reaperrr/limitedammo2
Refactored LimitedAmmo to AmmoPool
This commit is contained in:
@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
|
||||
{
|
||||
return new HeliAttack(newTarget);
|
||||
return new HeliAttack(self, newTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
|
||||
{
|
||||
return new FlyAttack(newTarget);
|
||||
return new FlyAttack(self, newTarget);
|
||||
}
|
||||
|
||||
protected override bool CanAttack(Actor self, Target target)
|
||||
|
||||
138
OpenRA.Mods.Common/Traits/AmmoPool.cs
Normal file
138
OpenRA.Mods.Common/Traits/AmmoPool.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Actor has a limited amount of ammo, after using it all the actor must reload in some way.")]
|
||||
public class AmmoPoolInfo : ITraitInfo
|
||||
{
|
||||
[Desc("Name of this ammo pool, used to link armaments to this pool.")]
|
||||
public readonly string Name = "primary";
|
||||
|
||||
[Desc("How much ammo does this pool contain when fully loaded.")]
|
||||
public readonly int Ammo = 1;
|
||||
|
||||
[Desc("Initial ammo the actor is created with. Defaults to Ammo.")]
|
||||
public readonly int InitialAmmo = -1;
|
||||
|
||||
[Desc("Defaults to value in Ammo. 0 means no visible pips.")]
|
||||
public readonly int PipCount = -1;
|
||||
|
||||
[Desc("PipType to use for loaded ammo.")]
|
||||
public readonly PipType PipType = PipType.Green;
|
||||
|
||||
[Desc("PipType to use for empty ammo.")]
|
||||
public readonly PipType PipTypeEmpty = PipType.Transparent;
|
||||
|
||||
[Desc("How much ammo is reloaded after a certain period.")]
|
||||
public readonly int ReloadCount = 1;
|
||||
|
||||
[Desc("Sound to play for each reloaded ammo magazine.")]
|
||||
public readonly string RearmSound = null;
|
||||
|
||||
[Desc("Time to reload per ReloadCount on airfield etc.")]
|
||||
public readonly int ReloadTicks = 25 * 2;
|
||||
|
||||
[Desc("Whether or not ammo is replenished on its own.")]
|
||||
public readonly bool SelfReloads = false;
|
||||
|
||||
[Desc("Time to reload per ReloadCount when actor 'SelfReloads'.")]
|
||||
public readonly int SelfReloadTicks = 25 * 2;
|
||||
|
||||
[Desc("Whether or not reload timer should be reset when ammo has been fired.")]
|
||||
public readonly bool ResetOnFire = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new AmmoPool(init.Self, this); }
|
||||
}
|
||||
|
||||
public class AmmoPool : INotifyAttack, IPips, ITick, ISync
|
||||
{
|
||||
public readonly AmmoPoolInfo Info;
|
||||
[Sync] public int CurrentAmmo;
|
||||
[Sync] public int RemainingTicks;
|
||||
public int PreviousAmmo;
|
||||
|
||||
public AmmoPool(Actor self, AmmoPoolInfo info)
|
||||
{
|
||||
Info = info;
|
||||
if (Info.InitialAmmo < Info.Ammo && Info.InitialAmmo >= 0)
|
||||
CurrentAmmo = Info.InitialAmmo;
|
||||
else
|
||||
CurrentAmmo = Info.Ammo;
|
||||
|
||||
RemainingTicks = Info.SelfReloadTicks;
|
||||
PreviousAmmo = GetAmmoCount();
|
||||
}
|
||||
|
||||
public int GetAmmoCount() { return CurrentAmmo; }
|
||||
public bool FullAmmo() { return CurrentAmmo == Info.Ammo; }
|
||||
public bool HasAmmo() { return CurrentAmmo > 0; }
|
||||
|
||||
public bool GiveAmmo()
|
||||
{
|
||||
if (CurrentAmmo >= Info.Ammo)
|
||||
return false;
|
||||
|
||||
++CurrentAmmo;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TakeAmmo()
|
||||
{
|
||||
if (CurrentAmmo <= 0)
|
||||
return false;
|
||||
|
||||
--CurrentAmmo;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Attacking(Actor self, Target target, Armament a, Barrel barrel)
|
||||
{
|
||||
if (a.Info.AmmoPoolName == Info.Name)
|
||||
TakeAmmo();
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!Info.SelfReloads)
|
||||
return;
|
||||
|
||||
// Resets the tick counter if ammo was fired.
|
||||
if (Info.ResetOnFire && GetAmmoCount() < PreviousAmmo)
|
||||
{
|
||||
RemainingTicks = Info.SelfReloadTicks;
|
||||
PreviousAmmo = GetAmmoCount();
|
||||
}
|
||||
|
||||
if (!FullAmmo() && --RemainingTicks == 0)
|
||||
{
|
||||
RemainingTicks = Info.SelfReloadTicks;
|
||||
|
||||
for (var i = 0; i < Info.ReloadCount; i++)
|
||||
GiveAmmo();
|
||||
|
||||
PreviousAmmo = GetAmmoCount();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PipType> GetPips(Actor self)
|
||||
{
|
||||
var pips = Info.PipCount >= 0 ? Info.PipCount : Info.Ammo;
|
||||
|
||||
return Enumerable.Range(0, pips).Select(i =>
|
||||
(CurrentAmmo * pips) / Info.Ammo > i ?
|
||||
Info.PipType : Info.PipTypeEmpty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,16 +31,25 @@ namespace OpenRA.Mods.Common.Traits
|
||||
[WeaponReference]
|
||||
[Desc("Has to be defined here and in weapons.yaml.")]
|
||||
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.")]
|
||||
public readonly string Turret = "primary";
|
||||
|
||||
[Desc("Time (in frames) until the weapon can fire again.")]
|
||||
public readonly int FireDelay = 0;
|
||||
|
||||
[Desc("Muzzle position relative to turret or body. (forward, right, up) triples")]
|
||||
public readonly WVec[] LocalOffset = { };
|
||||
|
||||
[Desc("Muzzle yaw relative to turret or body.")]
|
||||
public readonly WAngle[] LocalYaw = { };
|
||||
|
||||
[Desc("Move the turret backwards when firing.")]
|
||||
public readonly WRange Recoil = WRange.Zero;
|
||||
|
||||
[Desc("Recoil recovery per-frame")]
|
||||
public readonly WRange RecoilRecovery = new WRange(9);
|
||||
|
||||
@@ -64,7 +73,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
readonly Actor self;
|
||||
Lazy<Turreted> turret;
|
||||
Lazy<IBodyOrientation> coords;
|
||||
Lazy<LimitedAmmo> limitedAmmo;
|
||||
Lazy<AmmoPool> ammoPool;
|
||||
List<Pair<int, Action>> delayedActions = new List<Pair<int, Action>>();
|
||||
|
||||
public WRange Recoil;
|
||||
@@ -79,7 +88,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// We can't resolve these until runtime
|
||||
turret = Exts.Lazy(() => self.TraitsImplementing<Turreted>().FirstOrDefault(t => t.Name == info.Turret));
|
||||
coords = Exts.Lazy(() => self.Trait<IBodyOrientation>());
|
||||
limitedAmmo = Exts.Lazy(() => self.TraitOrDefault<LimitedAmmo>());
|
||||
ammoPool = Exts.Lazy(() => self.TraitsImplementing<AmmoPool>().FirstOrDefault(la => la.Info.Name == info.AmmoPoolName));
|
||||
|
||||
Weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()];
|
||||
Burst = Weapon.Burst;
|
||||
@@ -136,7 +145,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
if (IsReloading)
|
||||
return null;
|
||||
|
||||
if (limitedAmmo.Value != null && !limitedAmmo.Value.HasAmmo())
|
||||
if (ammoPool.Value != null && !ammoPool.Value.HasAmmo())
|
||||
return null;
|
||||
|
||||
if (!target.IsInRange(self.CenterPosition, Weapon.Range))
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Actor has a limited amount of ammo, after using it all the actor must reload in some way.")]
|
||||
public class LimitedAmmoInfo : ITraitInfo
|
||||
{
|
||||
public readonly int Ammo = 0;
|
||||
|
||||
[Desc("Defaults to value in Ammo.")]
|
||||
public readonly int PipCount = 0;
|
||||
|
||||
public readonly PipType PipType = PipType.Green;
|
||||
public readonly PipType PipTypeEmpty = PipType.Transparent;
|
||||
|
||||
[Desc("Time to reload measured in ticks.")]
|
||||
public readonly int ReloadTicks = 25 * 2;
|
||||
|
||||
public object Create(ActorInitializer init) { return new LimitedAmmo(this); }
|
||||
}
|
||||
|
||||
public class LimitedAmmo : INotifyAttack, IPips, ISync
|
||||
{
|
||||
[Sync] int ammo;
|
||||
LimitedAmmoInfo info;
|
||||
|
||||
public LimitedAmmo(LimitedAmmoInfo info)
|
||||
{
|
||||
ammo = info.Ammo;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public bool FullAmmo() { return ammo == info.Ammo; }
|
||||
public bool HasAmmo() { return ammo > 0; }
|
||||
public bool GiveAmmo()
|
||||
{
|
||||
if (ammo >= info.Ammo) return false;
|
||||
++ammo;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TakeAmmo()
|
||||
{
|
||||
if (ammo <= 0) return false;
|
||||
--ammo;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int ReloadTimePerAmmo() { return info.ReloadTicks; }
|
||||
|
||||
public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { TakeAmmo(); }
|
||||
|
||||
public int GetAmmoCount() { return ammo; }
|
||||
|
||||
public IEnumerable<PipType> GetPips(Actor self)
|
||||
{
|
||||
var pips = info.PipCount != 0 ? info.PipCount : info.Ammo;
|
||||
return Enumerable.Range(0, pips).Select(i =>
|
||||
(ammo * pips) / info.Ammo > i ?
|
||||
info.PipType : info.PipTypeEmpty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2015 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 OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("Unit will reload its limited ammo itself.")]
|
||||
public class ReloadsInfo : ITraitInfo, Requires<LimitedAmmoInfo>
|
||||
{
|
||||
[Desc("How much ammo is reloaded after a certain period.")]
|
||||
public readonly int Count = 0;
|
||||
[Desc("How long it takes to do so.")]
|
||||
public readonly int Period = 50;
|
||||
[Desc("Whether or not reload counter should be reset when ammo has been fired.")]
|
||||
public readonly bool ResetOnFire = false;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Reloads(init.Self, this); }
|
||||
}
|
||||
|
||||
public class Reloads : ITick
|
||||
{
|
||||
[Sync] int remainingTicks;
|
||||
ReloadsInfo info;
|
||||
LimitedAmmo la;
|
||||
int previousAmmo;
|
||||
|
||||
public Reloads(Actor self, ReloadsInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
remainingTicks = info.Period;
|
||||
la = self.Trait<LimitedAmmo>();
|
||||
previousAmmo = la.GetAmmoCount();
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!la.FullAmmo() && --remainingTicks == 0)
|
||||
{
|
||||
remainingTicks = info.Period;
|
||||
|
||||
for (var i = 0; i < info.Count; i++)
|
||||
la.GiveAmmo();
|
||||
|
||||
previousAmmo = la.GetAmmoCount();
|
||||
}
|
||||
|
||||
// Resets the tick counter if ammo was fired.
|
||||
if (info.ResetOnFire && la.GetAmmoCount() < previousAmmo)
|
||||
{
|
||||
remainingTicks = info.Period;
|
||||
previousAmmo = la.GetAmmoCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,18 +22,20 @@ namespace OpenRA.Mods.Common.Traits
|
||||
class RepairableInfo : ITraitInfo, Requires<HealthInfo>
|
||||
{
|
||||
public readonly string[] RepairBuildings = { "fix" };
|
||||
public virtual object Create(ActorInitializer init) { return new Repairable(init.Self); }
|
||||
public virtual object Create(ActorInitializer init) { return new Repairable(init.Self, this); }
|
||||
}
|
||||
|
||||
class Repairable : IIssueOrder, IResolveOrder, IOrderVoice
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly RepairableInfo info;
|
||||
readonly Health health;
|
||||
readonly IEnumerable<AmmoPool> ammoPools;
|
||||
|
||||
public Repairable(Actor self)
|
||||
public Repairable(Actor self, RepairableInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
health = self.Trait<Health>();
|
||||
ammoPools = self.TraitsImplementing<AmmoPool>();
|
||||
}
|
||||
|
||||
public IEnumerable<IOrderTargeter> Orders
|
||||
@@ -41,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
get
|
||||
{
|
||||
yield return new EnterAlliedActorTargeter<Building>("Repair", 5,
|
||||
target => CanRepairAt(target), _ => CanRepair());
|
||||
target => CanRepairAt(target), _ => CanRepair() || CanRearm());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,13 +57,25 @@ namespace OpenRA.Mods.Common.Traits
|
||||
|
||||
bool CanRepairAt(Actor target)
|
||||
{
|
||||
return self.Info.Traits.Get<RepairableInfo>().RepairBuildings.Contains(target.Info.Name);
|
||||
return info.RepairBuildings.Contains(target.Info.Name);
|
||||
}
|
||||
|
||||
bool CanRearmAt(Actor target)
|
||||
{
|
||||
return info.RepairBuildings.Contains(target.Info.Name);
|
||||
}
|
||||
|
||||
bool CanRepair()
|
||||
{
|
||||
var li = self.TraitOrDefault<LimitedAmmo>();
|
||||
return health.DamageState > DamageState.Undamaged || (li != null && !li.FullAmmo());
|
||||
return health.DamageState > DamageState.Undamaged;
|
||||
}
|
||||
|
||||
bool CanRearm()
|
||||
{
|
||||
if (ammoPools != null)
|
||||
return ammoPools.Any(x => !x.Info.SelfReloads && !x.FullAmmo());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
@@ -73,7 +87,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
if (order.OrderString == "Repair")
|
||||
{
|
||||
if (!CanRepairAt(order.TargetActor) || !CanRepair())
|
||||
if (!CanRepairAt(order.TargetActor) || (!CanRepair() && !CanRearm()))
|
||||
return;
|
||||
|
||||
var movement = self.Trait<IMove>();
|
||||
@@ -83,7 +97,9 @@ namespace OpenRA.Mods.Common.Traits
|
||||
self.CancelActivity();
|
||||
self.QueueActivity(new MoveAdjacentTo(self, target));
|
||||
self.QueueActivity(movement.MoveTo(self.World.Map.CellContaining(order.TargetActor.CenterPosition), order.TargetActor));
|
||||
self.QueueActivity(new Rearm(self));
|
||||
if (CanRearmAt(order.TargetActor) && CanRearm())
|
||||
self.QueueActivity(new Rearm(self));
|
||||
|
||||
self.QueueActivity(new Repair(order.TargetActor));
|
||||
|
||||
var rp = order.TargetActor.TraitOrDefault<RallyPoint>();
|
||||
|
||||
Reference in New Issue
Block a user