Merge cut missile-stats (Soul verdict cut-missile-stats.s2)
This commit is contained in:
commit
a19e3ba647
11 changed files with 539 additions and 29 deletions
|
|
@ -80,11 +80,13 @@ public static class CultRecordRefs
|
|||
{
|
||||
StatValidation.ValidateHeatResponse(data);
|
||||
StatValidation.ValidateStatModifiers(data.Name, data.Behaviors);
|
||||
StatValidation.ValidateMunitionParts(data.Name, data.Behaviors);
|
||||
StatValidation.ValidateRoleUsage(data.Name, data.Roles, data.Behaviors);
|
||||
}
|
||||
if (document is ConsumableItemData consumable)
|
||||
{
|
||||
StatValidation.ValidateStatModifiers(consumable.Name, consumable.Behaviors);
|
||||
StatValidation.ValidateMunitionParts(consumable.Name, consumable.Behaviors);
|
||||
StatValidation.ValidateRoleUsage(consumable.Name, consumable.Roles, consumable.Behaviors);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,6 +184,11 @@ public interface IPowerConsumer
|
|||
Union(40, typeof(MineLayerData)),
|
||||
Union(41, typeof(ThrottleLockData)),
|
||||
Union(42, typeof(VapourDumpData)),
|
||||
Union(43, typeof(MunitionHullData)),
|
||||
Union(44, typeof(MunitionThrusterData)),
|
||||
Union(45, typeof(MunitionSeekerData)),
|
||||
Union(46, typeof(MunitionControlData)),
|
||||
Union(47, typeof(MunitionFuelData)),
|
||||
JsonObject(MemberSerialization.OptIn)]
|
||||
public abstract class BehaviorData
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,14 +18,7 @@ public class LauncherData : LockWeaponData
|
|||
[InspectableAnimationCurve, JsonProperty("liftCurve"), Key(28)]
|
||||
public float4[] LiftCurve;
|
||||
|
||||
[Inspectable, JsonProperty("thrust"), Key(29)]
|
||||
public PerformanceStat Thrust = new PerformanceStat();
|
||||
|
||||
[Inspectable, JsonProperty("frequency"), Key(30)]
|
||||
public float DodgeFrequency;
|
||||
|
||||
[Inspectable, JsonProperty("missileSpeed"), Key(31), RuntimeInspectable]
|
||||
public PerformanceStat MissileVelocity = new PerformanceStat();
|
||||
// Keys 29-31 were Thrust, DodgeFrequency and MissileVelocity, retired for the munition parts (MunitionParts.cs); do not reuse.
|
||||
|
||||
public override Behavior CreateInstance(EquippedItem item)
|
||||
{
|
||||
|
|
@ -45,14 +38,7 @@ public class GuidedWeaponData : InstantWeaponData
|
|||
[InspectableAnimationCurve, JsonProperty("liftCurve"), Key(23)]
|
||||
public float4[] LiftCurve;
|
||||
|
||||
[Inspectable, JsonProperty("thrust"), Key(24)]
|
||||
public PerformanceStat Thrust = new PerformanceStat();
|
||||
|
||||
[Inspectable, JsonProperty("frequency"), Key(25)]
|
||||
public float DodgeFrequency;
|
||||
|
||||
[Inspectable, JsonProperty("missileSpeed"), Key(26), RuntimeInspectable]
|
||||
public PerformanceStat MissileVelocity = new PerformanceStat();
|
||||
// Keys 24-26 were Thrust, DodgeFrequency and MissileVelocity, retired for the munition parts (MunitionParts.cs); do not reuse.
|
||||
|
||||
public override Behavior CreateInstance(EquippedItem item)
|
||||
{
|
||||
|
|
|
|||
125
Assets/Scripts/ServerShared/Behaviors/MunitionParts.cs
Normal file
125
Assets/Scripts/ServerShared/Behaviors/MunitionParts.cs
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
// A missile type's stats, as five dedicated gear-part behaviours on the launcher's own design, one per gear
|
||||
// category the entity cut will derive them from (ruling drones-and-munitions-are-entities: "dedicated gear so a
|
||||
// missile thruster is not the same as a ship thruster"). Ruling missile-stats-now-gear-later, in the operator's
|
||||
// words: "For now these stats will belong to the missile, later they will be derived from gear." Each part becomes
|
||||
// a derivation from (or moves onto) that munition gear when munitions are entities.
|
||||
//
|
||||
// Each part is its own BehaviorData because every stat walker (role validation, StatModifier targeting, AetherDb
|
||||
// roles, the trade panel) reads PerformanceStat fields one level deep. The parts are inert: nothing here executes,
|
||||
// and no ship-wide reader (thrust allocator, sensing, signatures) reads them, because a missile thruster is not a
|
||||
// ship thruster and a seeker is not a ship sensor. MunitionParts.Of is the one read path.
|
||||
public abstract class MunitionPartData : BehaviorData
|
||||
{
|
||||
public override Behavior CreateInstance(EquippedItem item) => new MunitionPart(this, item);
|
||||
public override Behavior CreateInstance(ConsumableItemEffect consumable) => new MunitionPart(this, consumable);
|
||||
}
|
||||
|
||||
// What a part instantiates to: no state and no override, so Execute stays the default true.
|
||||
public sealed class MunitionPart : Behavior
|
||||
{
|
||||
public MunitionPart(MunitionPartData data, EquippedItem item) : base(data, item) { }
|
||||
public MunitionPart(MunitionPartData data, ConsumableItemEffect consumable) : base(data, consumable) { }
|
||||
}
|
||||
|
||||
public static class MunitionParts
|
||||
{
|
||||
// The design's one part of that type. Catalog load and Upsert refuse a munition without exactly one of each.
|
||||
public static T Of<T>(EquippedItem item) where T : MunitionPartData =>
|
||||
item.Behaviors.Select(b => b.Data).OfType<T>().Single();
|
||||
}
|
||||
|
||||
// The missile hull.
|
||||
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public sealed class MunitionHullData : MunitionPartData
|
||||
{
|
||||
[Inspectable, JsonProperty("durability"), Key(1), RuntimeInspectable]
|
||||
public PerformanceStat Durability = new PerformanceStat();
|
||||
|
||||
// Metres.
|
||||
[Inspectable, JsonProperty("radius"), Key(2)]
|
||||
public PerformanceStat Radius = new PerformanceStat();
|
||||
}
|
||||
|
||||
// The missile thruster.
|
||||
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public sealed class MunitionThrusterData : MunitionPartData
|
||||
{
|
||||
// The main motor, m/s^2.
|
||||
[Inspectable, JsonProperty("acceleration"), Key(1), RuntimeInspectable]
|
||||
public PerformanceStat Acceleration = new PerformanceStat();
|
||||
|
||||
// The sideways acceleration cap, m/s^2.
|
||||
[Inspectable, JsonProperty("lateral"), Key(2)]
|
||||
public PerformanceStat Lateral = new PerformanceStat();
|
||||
|
||||
// m/s.
|
||||
[Inspectable, JsonProperty("maxSpeed"), Key(3), RuntimeInspectable]
|
||||
public PerformanceStat MaxSpeed = new PerformanceStat();
|
||||
|
||||
// The strength of this motor's DrivePlume at full throttle, as ThrusterData.Visibility. A datum only: it is
|
||||
// never registered as the launching ship's signature.
|
||||
[Inspectable, JsonProperty("visibility"), Key(4)]
|
||||
public PerformanceStat Visibility = new PerformanceStat();
|
||||
}
|
||||
|
||||
// The seeker. Passive here: it reads a target and emits nothing.
|
||||
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public sealed class MunitionSeekerData : MunitionPartData
|
||||
{
|
||||
// Detection power, as SensorData.Sensitivity.
|
||||
[Inspectable, JsonProperty("sensitivity"), Key(1)]
|
||||
public PerformanceStat Sensitivity = new PerformanceStat();
|
||||
|
||||
// The full cone, in degrees (ruling sensor-stat-set's name and unit).
|
||||
[Inspectable, JsonProperty("beamWidth"), Key(2)]
|
||||
public PerformanceStat BeamWidth = new PerformanceStat();
|
||||
|
||||
// Metres.
|
||||
[Inspectable, JsonProperty("range"), Key(3)]
|
||||
public PerformanceStat Range = new PerformanceStat();
|
||||
}
|
||||
|
||||
// Guidance and its cognition.
|
||||
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public sealed class MunitionControlData : MunitionPartData
|
||||
{
|
||||
// The proportional-navigation constant.
|
||||
[Inspectable, JsonProperty("navigation"), Key(1)]
|
||||
public PerformanceStat Navigation = new PerformanceStat();
|
||||
|
||||
// The share of Lateral spent jinking.
|
||||
[Inspectable, JsonProperty("evasion"), Key(2)]
|
||||
public PerformanceStat Evasion = new PerformanceStat();
|
||||
|
||||
// Hz.
|
||||
[Inspectable, JsonProperty("evasionFrequency"), Key(3), RuntimeInspectable]
|
||||
public PerformanceStat EvasionFrequency = new PerformanceStat();
|
||||
|
||||
// Seconds.
|
||||
[Inspectable, JsonProperty("lifetime"), Key(4)]
|
||||
public PerformanceStat Lifetime = new PerformanceStat();
|
||||
|
||||
// The missile's own skill, 0 to 1 (ruling missile-cognition: "a smarter missile can better spend its delta v").
|
||||
// Four uses: guidance efficiency, when to jink against point defense, how much fuel it keeps for the terminal,
|
||||
// and the price of the hit.
|
||||
[Inspectable, JsonProperty("cognition"), Key(5)]
|
||||
public PerformanceStat Cognition = new PerformanceStat();
|
||||
}
|
||||
|
||||
// The tank.
|
||||
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public sealed class MunitionFuelData : MunitionPartData
|
||||
{
|
||||
// Total manoeuvre budget, m/s.
|
||||
[Inspectable, JsonProperty("deltaV"), Key(1)]
|
||||
public PerformanceStat DeltaV = new PerformanceStat();
|
||||
}
|
||||
11
Assets/Scripts/ServerShared/Behaviors/MunitionParts.cs.meta
Normal file
11
Assets/Scripts/ServerShared/Behaviors/MunitionParts.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6d4eac117ca042aaba71d1f6491b4617
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -815,6 +815,23 @@ public static class StatValidation
|
|||
}
|
||||
}
|
||||
|
||||
// Ruling missile-stats-now-gear-later: a munition design (a LauncherData or GuidedWeaponData behaviour) carries exactly
|
||||
// one of each of the five munition parts, and any other design carries none. Runs wherever ValidateStatModifiers runs,
|
||||
// so a launcher missing a part is named at catalog load and Upsert rather than at its first launch.
|
||||
public static void ValidateMunitionParts(string ownerName, IEnumerable<BehaviorData> behaviors)
|
||||
{
|
||||
var all = (behaviors ?? Enumerable.Empty<BehaviorData>()).Where(b => b != null).ToArray();
|
||||
var isMunition = all.Any(b => b is LauncherData || b is GuidedWeaponData);
|
||||
foreach (var part in new[] { typeof(MunitionHullData), typeof(MunitionThrusterData), typeof(MunitionSeekerData), typeof(MunitionControlData), typeof(MunitionFuelData) })
|
||||
{
|
||||
var count = all.Count(b => b.GetType() == part);
|
||||
var expected = isMunition ? 1 : 0;
|
||||
if (count != expected)
|
||||
throw new InvalidOperationException(
|
||||
$"{ownerName}: carries {count} {part.Name}, but a {(isMunition ? "munition" : "non-munition")} design carries {expected}");
|
||||
}
|
||||
}
|
||||
|
||||
// Cut 7 (docs/stats-and-power-cut.md): "a stat naming a role its design lacks" must be refused, not silently
|
||||
// fall back to the lot's own workmanship (Lot.QualityForRole already falls back for a role a lot never rolled
|
||||
// -- that is the intended forward-compat path for an old lot meeting a newly-authored role. This is the other
|
||||
|
|
|
|||
Loading…
Reference in a new issue