Remove RearmBuildings from Aircraft and Minelayer
In favor of using Rearmable trait.
This commit is contained in:
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
readonly MinelayerInfo info;
|
readonly MinelayerInfo info;
|
||||||
readonly AmmoPool[] ammoPools;
|
readonly AmmoPool[] ammoPools;
|
||||||
readonly IMove movement;
|
readonly IMove movement;
|
||||||
readonly HashSet<string> rearmBuildings;
|
readonly RearmableInfo rearmableInfo;
|
||||||
|
|
||||||
public LayMines(Actor self)
|
public LayMines(Actor self)
|
||||||
{
|
{
|
||||||
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
info = self.Info.TraitInfo<MinelayerInfo>();
|
info = self.Info.TraitInfo<MinelayerInfo>();
|
||||||
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
|
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
|
||||||
movement = self.Trait<IMove>();
|
movement = self.Trait<IMove>();
|
||||||
rearmBuildings = info.RearmBuildings;
|
rearmableInfo = self.Info.TraitInfoOrDefault<RearmableInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
@@ -43,11 +43,11 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
if (IsCanceled)
|
if (IsCanceled)
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
if (ammoPools != null && ammoPools.Any(p => p.Info.Name == info.AmmoPoolName && !p.HasAmmo()))
|
if (rearmableInfo != null && ammoPools.Any(p => p.Info.Name == info.AmmoPoolName && !p.HasAmmo()))
|
||||||
{
|
{
|
||||||
// Rearm (and possibly repair) at rearm building, then back out here to refill the minefield some more
|
// Rearm (and possibly repair) at rearm building, then back out here to refill the minefield some more
|
||||||
var rearmTarget = self.World.Actors.Where(a => self.Owner.Stances[a.Owner] == Stance.Ally
|
var rearmTarget = self.World.Actors.Where(a => self.Owner.Stances[a.Owner] == Stance.Ally
|
||||||
&& rearmBuildings.Contains(a.Info.Name))
|
&& rearmableInfo.RearmActors.Contains(a.Info.Name))
|
||||||
.ClosestTo(self);
|
.ClosestTo(self);
|
||||||
|
|
||||||
if (rearmTarget == null)
|
if (rearmTarget == null)
|
||||||
|
|||||||
@@ -21,10 +21,9 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Cnc.Traits
|
namespace OpenRA.Mods.Cnc.Traits
|
||||||
{
|
{
|
||||||
public class MinelayerInfo : ITraitInfo
|
public class MinelayerInfo : ITraitInfo, Requires<RearmableInfo>
|
||||||
{
|
{
|
||||||
[ActorReference] public readonly string Mine = "minv";
|
[ActorReference] public readonly string Mine = "minv";
|
||||||
[ActorReference] public readonly HashSet<string> RearmBuildings = new HashSet<string> { "fix" };
|
|
||||||
|
|
||||||
public readonly string AmmoPoolName = "primary";
|
public readonly string AmmoPoolName = "primary";
|
||||||
|
|
||||||
|
|||||||
@@ -443,22 +443,22 @@ namespace OpenRA.Mods.Common.AI
|
|||||||
CountBuildingByCommonName(Info.BuildingCommonNames.Barracks, Player) == 0;
|
CountBuildingByCommonName(Info.BuildingCommonNames.Barracks, Player) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For mods like RA (number of building must match the number of aircraft)
|
// For mods like RA (number of RearmActors must match the number of aircraft)
|
||||||
bool HasAdequateAirUnitReloadBuildings(ActorInfo actorInfo)
|
bool HasAdequateAirUnitReloadBuildings(ActorInfo actorInfo)
|
||||||
{
|
{
|
||||||
var aircraftInfo = actorInfo.TraitInfoOrDefault<AircraftInfo>();
|
var aircraftInfo = actorInfo.TraitInfoOrDefault<AircraftInfo>();
|
||||||
if (aircraftInfo == null)
|
if (aircraftInfo == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If the aircraft has at least 1 AmmoPool and defines 1 or more RearmBuildings, check if we have enough of those
|
// If actor isn't Rearmable, it doesn't need a RearmActor to reload
|
||||||
var hasAmmoPool = actorInfo.TraitInfos<AmmoPoolInfo>().Any();
|
var rearmableInfo = actorInfo.TraitInfoOrDefault<RearmableInfo>();
|
||||||
if (hasAmmoPool && aircraftInfo.RearmBuildings.Count > 0)
|
if (rearmableInfo == null)
|
||||||
{
|
return true;
|
||||||
var countOwnAir = CountActorsWithTrait<IPositionable>(actorInfo.Name, Player);
|
|
||||||
var countBuildings = aircraftInfo.RearmBuildings.Sum(b => CountActorsWithTrait<Building>(b, Player));
|
var countOwnAir = CountActorsWithTrait<IPositionable>(actorInfo.Name, Player);
|
||||||
if (countOwnAir >= countBuildings)
|
var countBuildings = rearmableInfo.RearmActors.Sum(b => CountActorsWithTrait<Building>(b, Player));
|
||||||
return false;
|
if (countOwnAir >= countBuildings)
|
||||||
}
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,11 @@ namespace OpenRA.Mods.Common.AI
|
|||||||
protected static bool ReloadsAutomatically(Actor a)
|
protected static bool ReloadsAutomatically(Actor a)
|
||||||
{
|
{
|
||||||
var ammoPools = a.TraitsImplementing<AmmoPool>();
|
var ammoPools = a.TraitsImplementing<AmmoPool>();
|
||||||
return ammoPools.All(x => x.AutoReloads);
|
var rearmable = a.TraitOrDefault<Rearmable>();
|
||||||
|
if (rearmable == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return ammoPools.All(ap => !rearmable.Info.AmmoPools.Contains(ap.Info.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static bool IsRearm(Actor a)
|
protected static bool IsRearm(Actor a)
|
||||||
|
|||||||
@@ -21,17 +21,17 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
readonly Target target;
|
readonly Target target;
|
||||||
readonly Aircraft aircraft;
|
readonly Aircraft aircraft;
|
||||||
readonly AttackPlane attackPlane;
|
readonly AttackPlane attackPlane;
|
||||||
|
readonly Rearmable rearmable;
|
||||||
|
|
||||||
readonly bool autoReloads;
|
|
||||||
int ticksUntilTurn;
|
int ticksUntilTurn;
|
||||||
|
|
||||||
public FlyAttack(Actor self, Target target)
|
public FlyAttack(Actor self, Target target)
|
||||||
{
|
{
|
||||||
this.target = target;
|
this.target = target;
|
||||||
aircraft = self.Trait<Aircraft>();
|
aircraft = self.Trait<Aircraft>();
|
||||||
attackPlane = self.TraitOrDefault<AttackPlane>();
|
attackPlane = self.Trait<AttackPlane>();
|
||||||
|
rearmable = self.TraitOrDefault<Rearmable>();
|
||||||
ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay;
|
ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay;
|
||||||
autoReloads = self.TraitsImplementing<AmmoPool>().All(p => p.AutoReloads);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
@@ -46,12 +46,11 @@ 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 and RearmBuilding is defined, return to RearmBuilding to reload and then resume the activity
|
// If all valid weapons have depleted their ammo and Rearmable trait exists, return to RearmActor to reload and then resume the activity
|
||||||
if (!autoReloads && aircraft.Info.RearmBuildings.Any() && attackPlane.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self)))
|
if (rearmable != null && 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)
|
attackPlane.DoAttack(self, target);
|
||||||
attackPlane.DoAttack(self, target);
|
|
||||||
|
|
||||||
if (ChildActivity == null)
|
if (ChildActivity == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
readonly Aircraft aircraft;
|
readonly Aircraft aircraft;
|
||||||
readonly AttackHeli attackHeli;
|
readonly AttackHeli attackHeli;
|
||||||
readonly bool attackOnlyVisibleTargets;
|
readonly bool attackOnlyVisibleTargets;
|
||||||
readonly bool autoReloads;
|
readonly Rearmable rearmable;
|
||||||
|
|
||||||
Target target;
|
Target target;
|
||||||
bool canHideUnderFog;
|
bool canHideUnderFog;
|
||||||
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
aircraft = self.Trait<Aircraft>();
|
aircraft = self.Trait<Aircraft>();
|
||||||
attackHeli = self.Trait<AttackHeli>();
|
attackHeli = self.Trait<AttackHeli>();
|
||||||
this.attackOnlyVisibleTargets = attackOnlyVisibleTargets;
|
this.attackOnlyVisibleTargets = attackOnlyVisibleTargets;
|
||||||
autoReloads = self.TraitsImplementing<AmmoPool>().All(p => p.AutoReloads);
|
rearmable = self.TraitOrDefault<Rearmable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
@@ -74,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 and RearmBuilding is defined, return to RearmBuilding to reload and then resume the activity
|
// If all valid weapons have depleted their ammo and Rearmable trait exists, return to RearmActor to reload and then resume the activity
|
||||||
if (!autoReloads && aircraft.Info.RearmBuildings.Any() && attackHeli.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self)))
|
if (rearmable != null && attackHeli.Armaments.All(x => x.IsTraitPaused || !x.Weapon.IsValidAgainst(target, self.World, self)))
|
||||||
return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, aircraft.Info.AbortOnResupply), this);
|
return ActivityUtils.SequenceActivities(new HeliReturnToBase(self, aircraft.Info.AbortOnResupply), this);
|
||||||
|
|
||||||
var dist = targetPos - pos;
|
var dist = targetPos - pos;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
{
|
{
|
||||||
readonly Aircraft aircraft;
|
readonly Aircraft aircraft;
|
||||||
readonly RepairableInfo repairableInfo;
|
readonly RepairableInfo repairableInfo;
|
||||||
|
readonly Rearmable rearmable;
|
||||||
readonly bool alwaysLand;
|
readonly bool alwaysLand;
|
||||||
readonly bool abortOnResupply;
|
readonly bool abortOnResupply;
|
||||||
Actor dest;
|
Actor dest;
|
||||||
@@ -28,6 +29,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
{
|
{
|
||||||
aircraft = self.Trait<Aircraft>();
|
aircraft = self.Trait<Aircraft>();
|
||||||
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>();
|
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>();
|
||||||
|
rearmable = self.TraitOrDefault<Rearmable>();
|
||||||
this.alwaysLand = alwaysLand;
|
this.alwaysLand = alwaysLand;
|
||||||
this.abortOnResupply = abortOnResupply;
|
this.abortOnResupply = abortOnResupply;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
@@ -35,9 +37,11 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
|
|
||||||
public Actor ChooseResupplier(Actor self, bool unreservedOnly)
|
public Actor ChooseResupplier(Actor self, bool unreservedOnly)
|
||||||
{
|
{
|
||||||
var rearmBuildings = aircraft.Info.RearmBuildings;
|
if (rearmable == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
return self.World.Actors.Where(a => a.Owner == self.Owner
|
return self.World.Actors.Where(a => a.Owner == self.Owner
|
||||||
&& rearmBuildings.Contains(a.Info.Name)
|
&& rearmable.Info.RearmActors.Contains(a.Info.Name)
|
||||||
&& (!unreservedOnly || !Reservable.IsReserved(a)))
|
&& (!unreservedOnly || !Reservable.IsReserved(a)))
|
||||||
.ClosestTo(self);
|
.ClosestTo(self);
|
||||||
}
|
}
|
||||||
@@ -119,8 +123,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
if (repairableInfo != null && repairableInfo.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged)
|
if (repairableInfo != null && repairableInfo.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return aircraft.Info.RearmBuildings.Contains(dest.Info.Name) && self.TraitsImplementing<AmmoPool>()
|
return rearmable != null && rearmable.Info.RearmActors.Contains(dest.Info.Name)
|
||||||
.Any(p => !p.AutoReloads && !p.FullAmmo());
|
&& rearmable.RearmableAmmoPools.Any(p => !p.FullAmmo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
readonly Aircraft aircraft;
|
readonly Aircraft aircraft;
|
||||||
readonly AircraftInfo aircraftInfo;
|
readonly AircraftInfo aircraftInfo;
|
||||||
readonly RepairableInfo repairableInfo;
|
readonly RepairableInfo repairableInfo;
|
||||||
|
readonly Rearmable rearmable;
|
||||||
readonly bool alwaysLand;
|
readonly bool alwaysLand;
|
||||||
readonly bool abortOnResupply;
|
readonly bool abortOnResupply;
|
||||||
bool isCalculated;
|
bool isCalculated;
|
||||||
@@ -37,14 +38,18 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
aircraft = self.Trait<Aircraft>();
|
aircraft = self.Trait<Aircraft>();
|
||||||
aircraftInfo = self.Info.TraitInfo<AircraftInfo>();
|
aircraftInfo = self.Info.TraitInfo<AircraftInfo>();
|
||||||
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>();
|
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>();
|
||||||
|
rearmable = self.TraitOrDefault<Rearmable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Actor ChooseResupplier(Actor self, bool unreservedOnly)
|
public static Actor ChooseResupplier(Actor self, bool unreservedOnly)
|
||||||
{
|
{
|
||||||
var rearmBuildings = self.Info.TraitInfo<AircraftInfo>().RearmBuildings;
|
var rearmInfo = self.Info.TraitInfoOrDefault<RearmableInfo>();
|
||||||
|
if (rearmInfo == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
return self.World.ActorsHavingTrait<Reservable>()
|
return self.World.ActorsHavingTrait<Reservable>()
|
||||||
.Where(a => a.Owner == self.Owner
|
.Where(a => a.Owner == self.Owner
|
||||||
&& rearmBuildings.Contains(a.Info.Name)
|
&& rearmInfo.RearmActors.Contains(a.Info.Name)
|
||||||
&& (!unreservedOnly || !Reservable.IsReserved(a)))
|
&& (!unreservedOnly || !Reservable.IsReserved(a)))
|
||||||
.ClosestTo(self);
|
.ClosestTo(self);
|
||||||
}
|
}
|
||||||
@@ -109,8 +114,8 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
if (repairableInfo != null && repairableInfo.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged)
|
if (repairableInfo != null && repairableInfo.RepairBuildings.Contains(dest.Info.Name) && self.GetDamageState() != DamageState.Undamaged)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return aircraftInfo.RearmBuildings.Contains(dest.Info.Name) && self.TraitsImplementing<AmmoPool>()
|
return rearmable != null && rearmable.Info.RearmActors.Contains(dest.Info.Name)
|
||||||
.Any(p => !p.AutoReloads && !p.FullAmmo());
|
&& rearmable.RearmableAmmoPools.Any(p => !p.FullAmmo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
{
|
{
|
||||||
readonly Target host;
|
readonly Target host;
|
||||||
readonly WDist closeEnough;
|
readonly WDist closeEnough;
|
||||||
readonly AmmoPool[] ammoPools;
|
readonly Rearmable rearmable;
|
||||||
|
|
||||||
public Rearm(Actor self, Actor host, WDist closeEnough)
|
public Rearm(Actor self, Actor host, WDist closeEnough)
|
||||||
{
|
{
|
||||||
this.host = Target.FromActor(host);
|
this.host = Target.FromActor(host);
|
||||||
this.closeEnough = closeEnough;
|
this.closeEnough = closeEnough;
|
||||||
ammoPools = self.TraitsImplementing<AmmoPool>().Where(p => !p.AutoReloads).ToArray();
|
rearmable = self.Trait<Rearmable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFirstRun(Actor self)
|
protected override void OnFirstRun(Actor self)
|
||||||
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
// Reset the ReloadDelay to avoid any issues with early cancellation
|
// Reset the ReloadDelay to avoid any issues with early cancellation
|
||||||
// from previous reload attempts (explicit order, host building died, etc).
|
// from previous reload attempts (explicit order, host building died, etc).
|
||||||
// HACK: this really shouldn't be managed from here
|
// HACK: this really shouldn't be managed from here
|
||||||
foreach (var pool in ammoPools)
|
foreach (var pool in rearmable.RearmableAmmoPools)
|
||||||
pool.RemainingTicks = pool.Info.ReloadDelay;
|
pool.RemainingTicks = pool.Info.ReloadDelay;
|
||||||
|
|
||||||
if (host.Type == TargetType.Invalid)
|
if (host.Type == TargetType.Invalid)
|
||||||
@@ -73,7 +73,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
return NextActivity;
|
return NextActivity;
|
||||||
|
|
||||||
var complete = true;
|
var complete = true;
|
||||||
foreach (var pool in ammoPools)
|
foreach (var pool in rearmable.RearmableAmmoPools)
|
||||||
{
|
{
|
||||||
if (!pool.FullAmmo())
|
if (!pool.FullAmmo())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -931,6 +931,7 @@
|
|||||||
<Compile Include="UpdateRules\Rules\20180923\LowPowerSlowdownToModifier.cs" />
|
<Compile Include="UpdateRules\Rules\20180923\LowPowerSlowdownToModifier.cs" />
|
||||||
<Compile Include="UpdateRules\Rules\20180923\RemoveHealthPercentageRing.cs" />
|
<Compile Include="UpdateRules\Rules\20180923\RemoveHealthPercentageRing.cs" />
|
||||||
<Compile Include="UpdateRules\Rules\20180923\RemoveRepairBuildingsFromAircraft.cs" />
|
<Compile Include="UpdateRules\Rules\20180923\RemoveRepairBuildingsFromAircraft.cs" />
|
||||||
|
<Compile Include="UpdateRules\Rules\20180923\AddRearmable.cs" />
|
||||||
<Compile Include="Traits\Player\PlayerResources.cs" />
|
<Compile Include="Traits\Player\PlayerResources.cs" />
|
||||||
<Compile Include="UtilityCommands\DumpSequenceSheetsCommand.cs" />
|
<Compile Include="UtilityCommands\DumpSequenceSheetsCommand.cs" />
|
||||||
<Compile Include="Traits\Render\WithBuildingRepairDecoration.cs" />
|
<Compile Include="Traits\Render\WithBuildingRepairDecoration.cs" />
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("The speed at which the aircraft is repulsed from other aircraft. Specify -1 for normal movement speed.")]
|
[Desc("The speed at which the aircraft is repulsed from other aircraft. Specify -1 for normal movement speed.")]
|
||||||
public readonly int RepulsionSpeed = -1;
|
public readonly int RepulsionSpeed = -1;
|
||||||
|
|
||||||
[ActorReference]
|
|
||||||
public readonly HashSet<string> RearmBuildings = new HashSet<string> { };
|
|
||||||
|
|
||||||
public readonly int InitialFacing = 0;
|
public readonly int InitialFacing = 0;
|
||||||
|
|
||||||
public readonly int TurnSpeed = 255;
|
public readonly int TurnSpeed = 255;
|
||||||
@@ -155,6 +152,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
|
|
||||||
RepairableInfo repairableInfo;
|
RepairableInfo repairableInfo;
|
||||||
|
RearmableInfo rearmableInfo;
|
||||||
ConditionManager conditionManager;
|
ConditionManager conditionManager;
|
||||||
IDisposable reservation;
|
IDisposable reservation;
|
||||||
IEnumerable<int> speedModifiers;
|
IEnumerable<int> speedModifiers;
|
||||||
@@ -211,6 +209,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
protected virtual void Created(Actor self)
|
protected virtual void Created(Actor self)
|
||||||
{
|
{
|
||||||
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>();
|
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>();
|
||||||
|
rearmableInfo = self.Info.TraitInfoOrDefault<RearmableInfo>();
|
||||||
conditionManager = self.TraitOrDefault<ConditionManager>();
|
conditionManager = self.TraitOrDefault<ConditionManager>();
|
||||||
speedModifiers = self.TraitsImplementing<ISpeedModifier>().ToArray().Select(sm => sm.GetSpeedModifier());
|
speedModifiers = self.TraitsImplementing<ISpeedModifier>().ToArray().Select(sm => sm.GetSpeedModifier());
|
||||||
cachedPosition = self.CenterPosition;
|
cachedPosition = self.CenterPosition;
|
||||||
@@ -450,7 +449,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (self.AppearsHostileTo(a))
|
if (self.AppearsHostileTo(a))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return Info.RearmBuildings.Contains(a.Info.Name)
|
return (rearmableInfo != null && rearmableInfo.RearmActors.Contains(a.Info.Name))
|
||||||
|| (repairableInfo != null && repairableInfo.RepairBuildings.Contains(a.Info.Name));
|
|| (repairableInfo != null && repairableInfo.RepairBuildings.Contains(a.Info.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,7 +486,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public virtual IEnumerable<Activity> GetResupplyActivities(Actor a)
|
public virtual IEnumerable<Activity> GetResupplyActivities(Actor a)
|
||||||
{
|
{
|
||||||
var name = a.Info.Name;
|
var name = a.Info.Name;
|
||||||
if (Info.RearmBuildings.Contains(name))
|
if (rearmableInfo != null && rearmableInfo.RearmActors.Contains(name))
|
||||||
yield return new Rearm(self, a, WDist.Zero);
|
yield return new Rearm(self, a, WDist.Zero);
|
||||||
|
|
||||||
// The ResupplyAircraft activity guarantees that we're on the helipad
|
// The ResupplyAircraft activity guarantees that we're on the helipad
|
||||||
@@ -669,13 +668,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued)
|
Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued)
|
||||||
{
|
{
|
||||||
if (!Info.RearmBuildings.Any())
|
if (rearmableInfo == null || !rearmableInfo.RearmActors.Any())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return new Order("ReturnToBase", self, queued);
|
return new Order("ReturnToBase", self, queued);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return Info.RearmBuildings.Any(); }
|
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return rearmableInfo != null && rearmableInfo.RearmActors.Any(); }
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
@@ -689,7 +688,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
case "Stop":
|
case "Stop":
|
||||||
return Info.Voice;
|
return Info.Voice;
|
||||||
case "ReturnToBase":
|
case "ReturnToBase":
|
||||||
return Info.RearmBuildings.Any() ? Info.Voice : null;
|
return rearmableInfo != null && rearmableInfo.RearmActors.Any() ? Info.Voice : null;
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -782,7 +781,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
self.QueueActivity(new HeliLand(self, true));
|
self.QueueActivity(new HeliLand(self, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (order.OrderString == "ReturnToBase" && Info.RearmBuildings.Any())
|
else if (order.OrderString == "ReturnToBase" && rearmableInfo != null && rearmableInfo.RearmActors.Any())
|
||||||
{
|
{
|
||||||
UnReserve();
|
UnReserve();
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.Traits
|
namespace OpenRA.Mods.Common.Traits
|
||||||
{
|
{
|
||||||
[Desc("Return to a player owned RearmBuildings. If none available, head back to base and circle over it.")]
|
[Desc("Return to a player owned RearmActor. If none available, head back to base and circle over it.")]
|
||||||
public class ReturnOnIdleInfo : ITraitInfo, Requires<AircraftInfo>
|
public class ReturnOnIdleInfo : ITraitInfo, Requires<AircraftInfo>
|
||||||
{
|
{
|
||||||
public object Create(ActorInitializer init) { return new ReturnOnIdle(init.Self, this); }
|
public object Create(ActorInitializer init) { return new ReturnOnIdle(init.Self, this); }
|
||||||
|
|||||||
@@ -97,15 +97,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This mostly serves to avoid complicated ReloadAmmoPool look-ups in various other places.
|
|
||||||
// TODO: Investigate removing this when the Rearm activity is replaced with a condition-based solution.
|
|
||||||
public bool AutoReloads { get; private set; }
|
|
||||||
|
|
||||||
void INotifyCreated.Created(Actor self)
|
void INotifyCreated.Created(Actor self)
|
||||||
{
|
{
|
||||||
conditionManager = self.TraitOrDefault<ConditionManager>();
|
conditionManager = self.TraitOrDefault<ConditionManager>();
|
||||||
AutoReloads = self.TraitsImplementing<ReloadAmmoPool>().Any(r => r.Info.AmmoPool == Info.Name && r.Info.RequiresCondition == null);
|
|
||||||
|
|
||||||
UpdateCondition(self);
|
UpdateCondition(self);
|
||||||
|
|
||||||
// HACK: Temporarily needed until Rearm activity is gone for good
|
// HACK: Temporarily needed until Rearm activity is gone for good
|
||||||
|
|||||||
@@ -32,19 +32,23 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public virtual object Create(ActorInitializer init) { return new Repairable(init.Self, this); }
|
public virtual object Create(ActorInitializer init) { return new Repairable(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Repairable : IIssueOrder, IResolveOrder, IOrderVoice
|
class Repairable : IIssueOrder, IResolveOrder, IOrderVoice, INotifyCreated
|
||||||
{
|
{
|
||||||
public readonly RepairableInfo Info;
|
public readonly RepairableInfo Info;
|
||||||
readonly IHealth health;
|
readonly IHealth health;
|
||||||
readonly IMove movement;
|
readonly IMove movement;
|
||||||
readonly AmmoPool[] ammoPools;
|
Rearmable rearmable;
|
||||||
|
|
||||||
public Repairable(Actor self, RepairableInfo info)
|
public Repairable(Actor self, RepairableInfo info)
|
||||||
{
|
{
|
||||||
Info = info;
|
Info = info;
|
||||||
health = self.Trait<IHealth>();
|
health = self.Trait<IHealth>();
|
||||||
movement = self.Trait<IMove>();
|
movement = self.Trait<IMove>();
|
||||||
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
|
}
|
||||||
|
|
||||||
|
void INotifyCreated.Created(Actor self)
|
||||||
|
{
|
||||||
|
rearmable = self.TraitOrDefault<Rearmable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IOrderTargeter> Orders
|
public IEnumerable<IOrderTargeter> Orders
|
||||||
@@ -70,7 +74,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
bool CanRearmAt(Actor target)
|
bool CanRearmAt(Actor target)
|
||||||
{
|
{
|
||||||
return Info.RepairBuildings.Contains(target.Info.Name);
|
return rearmable != null && rearmable.Info.RearmActors.Contains(target.Info.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanRepair()
|
bool CanRepair()
|
||||||
@@ -80,7 +84,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
bool CanRearm()
|
bool CanRearm()
|
||||||
{
|
{
|
||||||
return ammoPools.Any(x => !x.AutoReloads && !x.FullAmmo());
|
return rearmable != null && rearmable.RearmableAmmoPools.Any(p => !p.FullAmmo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
|
|||||||
102
OpenRA.Mods.Common/UpdateRules/Rules/20180923/AddRearmable.cs
Normal file
102
OpenRA.Mods.Common/UpdateRules/Rules/20180923/AddRearmable.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2018 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, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.UpdateRules.Rules
|
||||||
|
{
|
||||||
|
public class AddRearmable : UpdateRule
|
||||||
|
{
|
||||||
|
public override string Name { get { return "Added Rearmable trait and move RearmBuildings properties there"; } }
|
||||||
|
public override string Description
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Added Rearmable trait and replaced Aircraft.RearmBuildings and\n" +
|
||||||
|
"Minelayer.RearmBuildings with Rearmable.RearmActors.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
|
||||||
|
{
|
||||||
|
var aircraftNodes = actorNode.ChildrenMatching("Aircraft");
|
||||||
|
var minelayerNodes = actorNode.ChildrenMatching("Minelayer");
|
||||||
|
var ammoPoolNodes = actorNode.ChildrenMatching("AmmoPool");
|
||||||
|
var addNodes = new List<MiniYamlNode>();
|
||||||
|
|
||||||
|
var ammoPoolNames = new List<string>() { "primary" };
|
||||||
|
foreach (var ap in ammoPoolNodes)
|
||||||
|
{
|
||||||
|
var poolName = ap.LastChildMatching("Name");
|
||||||
|
if (poolName != null && poolName.NodeValue<string>() != "primary")
|
||||||
|
ammoPoolNames.Add(poolName.NodeValue<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
var rearmableAdded = false;
|
||||||
|
foreach (var aircraftNode in aircraftNodes)
|
||||||
|
{
|
||||||
|
var rearmBuildings = aircraftNode.LastChildMatching("RearmBuildings");
|
||||||
|
if (rearmBuildings != null)
|
||||||
|
{
|
||||||
|
if (!rearmableAdded)
|
||||||
|
{
|
||||||
|
var rearmableNode = new MiniYamlNode("Rearmable", "");
|
||||||
|
rearmBuildings.MoveAndRenameNode(aircraftNode, rearmableNode, "RearmActors");
|
||||||
|
|
||||||
|
// If the list has more than one entry, at least one of them won't be "primary"
|
||||||
|
if (ammoPoolNames.Count > 1)
|
||||||
|
{
|
||||||
|
var ammoPools = new MiniYamlNode("AmmoPools", string.Join(", ", ammoPoolNames));
|
||||||
|
rearmableNode.AddNode(ammoPools);
|
||||||
|
}
|
||||||
|
|
||||||
|
addNodes.Add(rearmableNode);
|
||||||
|
rearmableAdded = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aircraftNode.RemoveNodes("RearmBuildings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a minelayer, it won't be an aircraft and rearmableAdded should still be false, so we can use it here
|
||||||
|
foreach (var minelayerNode in minelayerNodes)
|
||||||
|
{
|
||||||
|
var rearmableNode = new MiniYamlNode("Rearmable", "");
|
||||||
|
|
||||||
|
var rearmBuildings = minelayerNode.LastChildMatching("RearmBuildings");
|
||||||
|
if (!rearmableAdded)
|
||||||
|
{
|
||||||
|
if (rearmBuildings != null)
|
||||||
|
rearmBuildings.MoveAndRenameNode(minelayerNode, rearmableNode, "RearmActors");
|
||||||
|
else
|
||||||
|
rearmableNode.AddNode(new MiniYamlNode("RearmActors", "fix"));
|
||||||
|
|
||||||
|
// If the list has more than one entry, at least one of them won't be "primary"
|
||||||
|
if (ammoPoolNames.Count > 1)
|
||||||
|
{
|
||||||
|
var ammoPools = new MiniYamlNode("AmmoPools", string.Join(", ", ammoPoolNames));
|
||||||
|
rearmableNode.AddNode(ammoPools);
|
||||||
|
}
|
||||||
|
|
||||||
|
addNodes.Add(rearmableNode);
|
||||||
|
rearmableAdded = true;
|
||||||
|
}
|
||||||
|
else if (rearmableAdded && rearmBuildings != null)
|
||||||
|
minelayerNode.RemoveNodes("RearmBuildings");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var node in addNodes)
|
||||||
|
actorNode.AddNode(node);
|
||||||
|
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,6 +100,7 @@ namespace OpenRA.Mods.Common.UpdateRules
|
|||||||
new RemoveHealthPercentageRing(),
|
new RemoveHealthPercentageRing(),
|
||||||
new RenameCrateActionNotification(),
|
new RenameCrateActionNotification(),
|
||||||
new RemoveRepairBuildingsFromAircraft(),
|
new RemoveRepairBuildingsFromAircraft(),
|
||||||
|
new AddRearmable(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ MIG:
|
|||||||
AttackPlane:
|
AttackPlane:
|
||||||
FacingTolerance: 20
|
FacingTolerance: 20
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: afld, afld.ukraine
|
|
||||||
CruiseAltitude: 2560
|
CruiseAltitude: 2560
|
||||||
InitialFacing: 192
|
InitialFacing: 192
|
||||||
TurnSpeed: 4
|
TurnSpeed: 4
|
||||||
@@ -138,6 +137,8 @@ MIG:
|
|||||||
Interval: 2
|
Interval: 2
|
||||||
ProducibleWithLevel:
|
ProducibleWithLevel:
|
||||||
Prerequisites: aircraft.upgraded
|
Prerequisites: aircraft.upgraded
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: afld, afld.ukraine
|
||||||
|
|
||||||
YAK:
|
YAK:
|
||||||
Inherits: ^Plane
|
Inherits: ^Plane
|
||||||
@@ -175,7 +176,6 @@ YAK:
|
|||||||
AttackPlane:
|
AttackPlane:
|
||||||
FacingTolerance: 20
|
FacingTolerance: 20
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: afld, afld.ukraine
|
|
||||||
CruiseAltitude: 2560
|
CruiseAltitude: 2560
|
||||||
InitialFacing: 192
|
InitialFacing: 192
|
||||||
TurnSpeed: 4
|
TurnSpeed: 4
|
||||||
@@ -204,6 +204,8 @@ YAK:
|
|||||||
Prerequisites: aircraft.upgraded
|
Prerequisites: aircraft.upgraded
|
||||||
Selectable:
|
Selectable:
|
||||||
DecorationBounds: 30,28,0,2
|
DecorationBounds: 30,28,0,2
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: afld, afld.ukraine
|
||||||
|
|
||||||
TRAN:
|
TRAN:
|
||||||
Inherits: ^Helicopter
|
Inherits: ^Helicopter
|
||||||
@@ -292,7 +294,6 @@ HELI:
|
|||||||
AttackHeli:
|
AttackHeli:
|
||||||
FacingTolerance: 20
|
FacingTolerance: 20
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: hpad
|
|
||||||
LandWhenIdle: false
|
LandWhenIdle: false
|
||||||
InitialFacing: 224
|
InitialFacing: 224
|
||||||
TurnSpeed: 4
|
TurnSpeed: 4
|
||||||
@@ -320,6 +321,8 @@ HELI:
|
|||||||
Prerequisites: aircraft.upgraded
|
Prerequisites: aircraft.upgraded
|
||||||
Selectable:
|
Selectable:
|
||||||
DecorationBounds: 36,28
|
DecorationBounds: 36,28
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: hpad
|
||||||
|
|
||||||
HIND:
|
HIND:
|
||||||
Inherits: ^Helicopter
|
Inherits: ^Helicopter
|
||||||
@@ -357,7 +360,6 @@ HIND:
|
|||||||
AttackHeli:
|
AttackHeli:
|
||||||
FacingTolerance: 20
|
FacingTolerance: 20
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: hpad
|
|
||||||
LandWhenIdle: false
|
LandWhenIdle: false
|
||||||
InitialFacing: 224
|
InitialFacing: 224
|
||||||
TurnSpeed: 4
|
TurnSpeed: 4
|
||||||
@@ -386,6 +388,8 @@ HIND:
|
|||||||
Prerequisites: aircraft.upgraded
|
Prerequisites: aircraft.upgraded
|
||||||
Selectable:
|
Selectable:
|
||||||
DecorationBounds: 38,32
|
DecorationBounds: 38,32
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: hpad
|
||||||
|
|
||||||
U2:
|
U2:
|
||||||
Inherits: ^NeutralPlane
|
Inherits: ^NeutralPlane
|
||||||
|
|||||||
@@ -492,6 +492,8 @@ MNLY:
|
|||||||
Weapon: ATMine
|
Weapon: ATMine
|
||||||
RenderSprites:
|
RenderSprites:
|
||||||
Image: MNLY
|
Image: MNLY
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: fix
|
||||||
|
|
||||||
TRUK:
|
TRUK:
|
||||||
Inherits: ^Vehicle
|
Inherits: ^Vehicle
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ ORCA:
|
|||||||
Selectable:
|
Selectable:
|
||||||
Bounds: 30,24
|
Bounds: 30,24
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: gahpad, nahpad
|
|
||||||
TurnSpeed: 5
|
TurnSpeed: 5
|
||||||
Speed: 186
|
Speed: 186
|
||||||
MoveIntoShroud: false
|
MoveIntoShroud: false
|
||||||
@@ -109,6 +108,8 @@ ORCA:
|
|||||||
RenderSprites:
|
RenderSprites:
|
||||||
SpawnActorOnDeath:
|
SpawnActorOnDeath:
|
||||||
Actor: ORCA.Husk
|
Actor: ORCA.Husk
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: gahpad, nahpad
|
||||||
|
|
||||||
ORCAB:
|
ORCAB:
|
||||||
Inherits: ^Aircraft
|
Inherits: ^Aircraft
|
||||||
@@ -127,7 +128,6 @@ ORCAB:
|
|||||||
Selectable:
|
Selectable:
|
||||||
Bounds: 30,24
|
Bounds: 30,24
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: gahpad, nahpad
|
|
||||||
CruiseAltitude: 3072
|
CruiseAltitude: 3072
|
||||||
MaximumPitch: 120
|
MaximumPitch: 120
|
||||||
TurnSpeed: 3
|
TurnSpeed: 3
|
||||||
@@ -164,6 +164,8 @@ ORCAB:
|
|||||||
RequiresCondition: cruising
|
RequiresCondition: cruising
|
||||||
SpawnActorOnDeath:
|
SpawnActorOnDeath:
|
||||||
Actor: ORCAB.Husk
|
Actor: ORCAB.Husk
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: gahpad, nahpad
|
||||||
|
|
||||||
ORCATRAN:
|
ORCATRAN:
|
||||||
Inherits: ^Helicopter
|
Inherits: ^Helicopter
|
||||||
@@ -257,7 +259,6 @@ SCRIN:
|
|||||||
Voiced:
|
Voiced:
|
||||||
VoiceSet: Scrin
|
VoiceSet: Scrin
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: gahpad, nahpad
|
|
||||||
CruiseAltitude: 2560
|
CruiseAltitude: 2560
|
||||||
MaximumPitch: 90
|
MaximumPitch: 90
|
||||||
TurnSpeed: 3
|
TurnSpeed: 3
|
||||||
@@ -292,6 +293,8 @@ SCRIN:
|
|||||||
DeathSounds:
|
DeathSounds:
|
||||||
SpawnActorOnDeath:
|
SpawnActorOnDeath:
|
||||||
Actor: SCRIN.Husk
|
Actor: SCRIN.Husk
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: gahpad, nahpad
|
||||||
|
|
||||||
APACHE:
|
APACHE:
|
||||||
Inherits: ^Helicopter
|
Inherits: ^Helicopter
|
||||||
@@ -310,7 +313,6 @@ APACHE:
|
|||||||
Selectable:
|
Selectable:
|
||||||
Bounds: 30,24
|
Bounds: 30,24
|
||||||
Aircraft:
|
Aircraft:
|
||||||
RearmBuildings: gahpad, nahpad
|
|
||||||
TurnSpeed: 5
|
TurnSpeed: 5
|
||||||
Speed: 130
|
Speed: 130
|
||||||
MoveIntoShroud: false
|
MoveIntoShroud: false
|
||||||
@@ -345,6 +347,8 @@ APACHE:
|
|||||||
RenderSprites:
|
RenderSprites:
|
||||||
SpawnActorOnDeath:
|
SpawnActorOnDeath:
|
||||||
Actor: APACHE.Husk
|
Actor: APACHE.Husk
|
||||||
|
Rearmable:
|
||||||
|
RearmActors: gahpad, nahpad
|
||||||
|
|
||||||
HUNTER:
|
HUNTER:
|
||||||
Inherits@2: ^ExistsInWorld
|
Inherits@2: ^ExistsInWorld
|
||||||
|
|||||||
Reference in New Issue
Block a user