Merge nibu/ammo-tail into nibu/suite-honest
This commit is contained in:
commit
663d054b02
15 changed files with 252 additions and 39 deletions
|
|
@ -46,6 +46,7 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior, IPowerC
|
|||
{
|
||||
get => _ammo;
|
||||
}
|
||||
public override bool HasMagazine => false;
|
||||
|
||||
public float Progress
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,6 +104,12 @@ public abstract class Weapon : ActivatedBehavior
|
|||
public abstract int Ammo { get; }
|
||||
// Rounds in the ship's cargo that reload this weapon's magazine: crates of AmmoType, 0 when the weapon draws none.
|
||||
public int Reserve => _data.AmmoType.IsSet() ? Entity.CountItemsInCargo(_data.AmmoType.Key) : 0;
|
||||
// Whether Ammo counts a magazine. A weapon that names an AmmoType and fires from one (InstantWeapon) does; a beam (ConstantWeapon) draws one
|
||||
// crate per AmmoInterval straight from the cargo and has none.
|
||||
public virtual bool HasMagazine => true;
|
||||
// What the HUD's ammunition label shows: "magazine/reserve" for a magazine weapon, the reserve alone for one without a magazine, empty when
|
||||
// the weapon draws no ammunition. The one rule the HUD reads, so the label cannot show a magazine a weapon does not have.
|
||||
public string AmmoReadout => !_data.AmmoType.IsSet() ? "" : HasMagazine ? $"{Ammo}/{Reserve}" : Reserve.ToString();
|
||||
public WeaponData WeaponData => _data;
|
||||
public float RangeFactor(float at) => WeaponData.RangeFactor(MinRange, EffectiveRange, Range, _data.DamageAtMaxRange, at);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,16 +32,13 @@ public static class Extensions
|
|||
|
||||
// Every loadable type assignable to this one. An assembly whose dependencies are missing (a Unity plugin
|
||||
// referencing UnityEngine outside Unity) still yields the types that do load.
|
||||
private static readonly Dictionary<Type, Type[]> ChildClasses = new Dictionary<Type, Type[]>();
|
||||
public static Type[] GetAllChildClasses(this Type type)
|
||||
// Read from parallel loaders (catalog validation, parallel tests), so the memo is concurrent.
|
||||
private static readonly System.Collections.Concurrent.ConcurrentDictionary<Type, Type[]> ChildClasses = new System.Collections.Concurrent.ConcurrentDictionary<Type, Type[]>();
|
||||
public static Type[] GetAllChildClasses(this Type type) => ChildClasses.GetOrAdd(type, t => AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly =>
|
||||
{
|
||||
if (ChildClasses.TryGetValue(type, out var children)) return children;
|
||||
return ChildClasses[type] = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly =>
|
||||
{
|
||||
try { return assembly.GetTypes(); }
|
||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); }
|
||||
}).Where(type.IsAssignableFrom).ToArray();
|
||||
}
|
||||
try { return assembly.GetTypes(); }
|
||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(x => x != null); }
|
||||
}).Where(t.IsAssignableFrom).ToArray());
|
||||
|
||||
public static string SplitCamelCase(this string str) =>
|
||||
Regex.Replace(Regex.Replace(str, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2");
|
||||
|
|
|
|||
|
|
@ -168,7 +168,8 @@ public sealed class ScenarioStage
|
|||
}
|
||||
|
||||
// Items in the entity's first cargo bay, one per name. A name is an equippable or consumable design (open: the stage
|
||||
// chooses its product) or a product of one (pinned); a name that is neither is a failure.
|
||||
// chooses its product) or a product of one (pinned), or a commodity (one unit: the crates an AmmoType weapon reloads
|
||||
// from); a name that is none of these is a failure.
|
||||
public void Cargo(Entity entity, params string[] names)
|
||||
{
|
||||
if (entity == null) return;
|
||||
|
|
@ -177,6 +178,13 @@ public sealed class ScenarioStage
|
|||
var bay = entity.CargoBays.FirstOrDefault();
|
||||
foreach (var name in names)
|
||||
{
|
||||
var commodity = _items.ItemData.GetAll<SimpleCommodityData>().FirstOrDefault(data => data.Name == name);
|
||||
if (commodity != null)
|
||||
{
|
||||
if (bay == null || !bay.TryStore(new SimpleCommodity { Data = new CultRecordRef<ItemData>(_items.ItemData.RefOf<ItemData>(commodity).Key), Quantity = 1 }))
|
||||
_failures.Add($"{where}: no room for {name}");
|
||||
continue;
|
||||
}
|
||||
var (data, product) = NamedOrProduct<CraftedItemData>(name, where, found => found is EquippableItemData || found is ConsumableItemData);
|
||||
if (data == null) continue;
|
||||
var build = Loadouts.Resolve(_items, _items.ItemData.RefOf(data),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Linq;
|
||||
using static CultMath.math;
|
||||
using static ItemRotation;
|
||||
|
||||
|
|
@ -20,6 +21,8 @@ public sealed class Arcs : Scenario
|
|||
public static readonly CultMath.float2 Bow = float2(0, 400), Stern = float2(0, -400), Turret = float2(600, 300),
|
||||
Port = float2(-400, 0), Starboard = float2(400, 0);
|
||||
|
||||
public const int TurretAmmoCrates = 30;
|
||||
|
||||
public override Galaxy Generate(GalaxyStage stage) => stage.Prelude();
|
||||
|
||||
public override void Stage(ScenarioStage stage)
|
||||
|
|
@ -49,12 +52,14 @@ public sealed class Arcs : Scenario
|
|||
("Compact Reactor", int2(3, 3), None),
|
||||
("Turret Control Module", int2(3, 5), None),
|
||||
("not if i see you first", int2(4, 5), None), // Compact Sensor
|
||||
("Panopticon Prime", int2(3, 6), None)); // Fire Control Array
|
||||
("Panopticon Prime", int2(3, 6), None), // Fire Control Array
|
||||
("Store-All Plus", int2(3, 1), None)); // Cargo Bay: the only 2x2 the turret hull has free
|
||||
|
||||
stage.Player(fighter, float2(0, 0), facing: float2(0, 1));
|
||||
stage.Place(stage.Bare("Longinus"), Bow);
|
||||
stage.Place(stage.Bare("Longinus"), Stern);
|
||||
stage.Place(turret, Turret, stance: ScenarioStance.Hostile);
|
||||
// The turret's guns reload from its hold, a crate of Ammo per 100-round magazine: both guns firing without pause spend about 3.5 crates a minute, so 30 outlast any session.
|
||||
stage.Cargo(stage.Place(turret, Turret, stance: ScenarioStance.Hostile), Enumerable.Repeat("Ammo", TurretAmmoCrates).ToArray());
|
||||
stage.Place(stage.Bare("Longinus"), Port);
|
||||
stage.Place(stage.Bare("Longinus"), Starboard);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Linq;
|
||||
using static CultMath.math;
|
||||
using static ItemRotation;
|
||||
|
||||
|
|
@ -7,6 +8,7 @@ public sealed class Pursuit : Scenario
|
|||
// cloud breaking a sensor's lock, and well outside the 40 at which AStrongCloseSensorBurnsThrough shows a close
|
||||
// sensor burning through.
|
||||
private const float Astern = 300;
|
||||
public const int MineCrates = 10;
|
||||
|
||||
public override string Name => "Pursuit";
|
||||
public override string Id => "pursuit";
|
||||
|
|
@ -55,7 +57,8 @@ public sealed class Pursuit : Scenario
|
|||
("Store-All Plus", int2(2, 8), None)); // Cargo Bay
|
||||
|
||||
var player = stage.Player(layer, float2(0, 0), facing: float2(0, 1));
|
||||
stage.Cargo(player, "Morning Fog", "Morning Fog", "Morning Fog", "send it", "send it");
|
||||
// The Mine Launcher reloads a magazine of six from a crate of Mines: ten crates are sixty-six mines, minutes of laying at its cooldown, more than a chase lasts.
|
||||
stage.Cargo(player, new[] { "Morning Fog", "Morning Fog", "Morning Fog", "send it", "send it" }.Concat(Enumerable.Repeat("Mines", MineCrates)).ToArray());
|
||||
stage.Place(pursuer, float2(0, -Astern), facing: float2(0, 1), stance: ScenarioStance.Hostile, piloted: true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue