2026-08-10 14:57:50 +01:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2020-12-22 03:13:43 +00:00
|
|
|
|
* 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;
|
2020-12-01 00:16:11 +00:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
using MessagePack;
|
|
|
|
|
|
using Newtonsoft.Json;
|
2026-09-14 17:39:12 +02:00
|
|
|
|
using CultMath;
|
|
|
|
|
|
using static CultMath.math;
|
2020-12-01 00:16:11 +00:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public class PlanetSettings
|
|
|
|
|
|
{
|
|
|
|
|
|
public ExponentialCurve LightRadius;
|
|
|
|
|
|
public ExponentialCurve BodyRadius;
|
Gravity: one potential per zone owns acceleration and height
GravityField is the law of one well (logarithmic tail, softened core).
Zone.GetForce and GetHeight sum it over the bodies; GetNormal derives from
the force for ship tilt; Flow and Ship read GetForce. Well strength, core
radius and Roche limit are PlanetSettings curves of mass, height
exaggeration K one global. Deletes GravityAcceleration, GravityReferenceRate,
GravityStrength, the PowerPulse well, GetNormal's finite differences and
BodyData.GravityDepthExponent. Settings.asset carries the calibrated curves.
Tests: PotentialOwnerTests, the moon's moon placement, retired keys over every
BodyData type, a body-derived giant sweep. Not yet built or run (verify job
follows); this commit may not build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:36:28 +02:00
|
|
|
|
|
Well law: the band term, WellTree owns every term; the old law, per-body sums and Gauss ring law deleted
GravityField is now the band term U(eps, inner, outer) (C4 smoothstep fade, closed form and a series for tau > 1).
WellTree is built once per Zone from the orbit tree: node terms, reach, support, the pruned Force/Potential walk and
PullAround (rails). Zone.GetHeight/GetForce/PeriodAround delegate to it; WellReference, _wellOn, _strengths,
Strength() and DrawAhead.Well are gone; GravityLowering and the shader template take the flat term list;
HeightExaggeration halves to 2.0491803.
Does not pass yet: Gravity.cginc is not regenerated and PotentialOwnerTests/OrbitsFromFieldTests still spell the old law.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:56:25 +02:00
|
|
|
|
// The closest a child may orbit its parent, in u, by the parent's mass, and the Plummer softening of the parent's
|
|
|
|
|
|
// well (the steepest slope, 0.5 c / eps, sits at the Roche limit). Authored like BodyRadius, never per body.
|
Gravity: one potential per zone owns acceleration and height
GravityField is the law of one well (logarithmic tail, softened core).
Zone.GetForce and GetHeight sum it over the bodies; GetNormal derives from
the force for ship tilt; Flow and Ship read GetForce. Well strength, core
radius and Roche limit are PlanetSettings curves of mass, height
exaggeration K one global. Deletes GravityAcceleration, GravityReferenceRate,
GravityStrength, the PowerPulse well, GetNormal's finite differences and
BodyData.GravityDepthExponent. Settings.asset carries the calibrated curves.
Tests: PotentialOwnerTests, the moon's moon placement, retired keys over every
BodyData type, a body-derived giant sweep. Not yet built or run (verify job
follows); this commit may not build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:36:28 +02:00
|
|
|
|
public ExponentialCurve RocheLimit = new ExponentialCurve();
|
|
|
|
|
|
|
Well law: the band term, WellTree owns every term; the old law, per-body sums and Gauss ring law deleted
GravityField is now the band term U(eps, inner, outer) (C4 smoothstep fade, closed form and a series for tau > 1).
WellTree is built once per Zone from the orbit tree: node terms, reach, support, the pruned Force/Potential walk and
PullAround (rails). Zone.GetHeight/GetForce/PeriodAround delegate to it; WellReference, _wellOn, _strengths,
Strength() and DrawAhead.Well are gone; GravityLowering and the shader template take the flat term list;
HeightExaggeration halves to 2.0491803.
Does not pass yet: Gravity.cginc is not regenerated and PotentialOwnerTests/OrbitsFromFieldTests still spell the old law.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 17:56:25 +02:00
|
|
|
|
// A body's well strength by its mass (GravityField): c in u^2/s^2. The pull is c d / (d^2 + eps^2) inside a family and
|
|
|
|
|
|
// c(family mass) beyond it (WellTree); eps is the Roche limit.
|
Gravity: one potential per zone owns acceleration and height
GravityField is the law of one well (logarithmic tail, softened core).
Zone.GetForce and GetHeight sum it over the bodies; GetNormal derives from
the force for ship tilt; Flow and Ship read GetForce. Well strength, core
radius and Roche limit are PlanetSettings curves of mass, height
exaggeration K one global. Deletes GravityAcceleration, GravityReferenceRate,
GravityStrength, the PowerPulse well, GetNormal's finite differences and
BodyData.GravityDepthExponent. Settings.asset carries the calibrated curves.
Tests: PotentialOwnerTests, the moon's moon placement, retired keys over every
BodyData type, a body-derived giant sweep. Not yet built or run (verify job
follows); this commit may not build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:36:28 +02:00
|
|
|
|
public ExponentialCurve WellStrength = new ExponentialCurve();
|
|
|
|
|
|
|
|
|
|
|
|
// The one global exaggeration of gravity height: height = potential / K, in u/s^2 per unit of height.
|
|
|
|
|
|
public float HeightExaggeration = 1f;
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public ExponentialLerp AsteroidSize;
|
|
|
|
|
|
public ExponentialLerp AsteroidHitpoints;
|
|
|
|
|
|
public ExponentialLerp AsteroidRespawnTime;
|
2021-05-11 04:45:42 +01:00
|
|
|
|
public float SecureAreaRadiusMultiplier = .45f;
|
2020-12-01 00:16:11 +00:00
|
|
|
|
|
2026-10-13 20:06:35 +02:00
|
|
|
|
|
|
|
|
|
|
// The global flow stardust and nebula follow and the sim knows (FlowField). Zero flow by default.
|
|
|
|
|
|
public FlowSettings Flow = new FlowSettings();
|
2020-12-01 00:16:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public class GalaxyShapeSettings
|
|
|
|
|
|
{
|
|
|
|
|
|
public int Arms = 4;
|
|
|
|
|
|
public float Twist = 10;
|
|
|
|
|
|
public float TwistExponent = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
|
2021-04-22 02:53:06 +01:00
|
|
|
|
public class SectorBackgroundSettings
|
|
|
|
|
|
{
|
2021-03-10 09:18:07 +00:00
|
|
|
|
public float NoiseAmplitude;
|
|
|
|
|
|
public float NoiseOffset;
|
|
|
|
|
|
public float NoiseGain;
|
|
|
|
|
|
public float NoiseLacunarity;
|
|
|
|
|
|
public float NoiseFrequency;
|
2021-04-22 02:53:06 +01:00
|
|
|
|
public float NoisePosition;
|
|
|
|
|
|
public float CloudExponent;
|
|
|
|
|
|
public float CloudAmplitude;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2021-03-10 09:18:07 +00:00
|
|
|
|
public float fBm(float2 p, int octaves)
|
|
|
|
|
|
{
|
|
|
|
|
|
float freq = NoiseFrequency, amp = .5f;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
float sum = 0;
|
|
|
|
|
|
for(int i = 0; i < octaves; i++)
|
2021-03-10 09:18:07 +00:00
|
|
|
|
{
|
|
|
|
|
|
if(i<4)
|
2026-08-10 14:57:50 +01:00
|
|
|
|
sum += (1-abs(snoise(p * freq))) * amp;
|
|
|
|
|
|
else sum += abs(snoise(p * freq)) * amp;
|
2021-03-10 09:18:07 +00:00
|
|
|
|
freq *= NoiseLacunarity;
|
|
|
|
|
|
amp *= NoiseGain;
|
|
|
|
|
|
}
|
|
|
|
|
|
return (sum + NoiseOffset)*NoiseAmplitude;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public float CloudDensity(float2 uv)
|
|
|
|
|
|
{
|
2021-03-15 11:40:46 +00:00
|
|
|
|
float noise = fBm(uv + NoisePosition, 10);
|
2026-08-10 14:57:50 +01:00
|
|
|
|
return pow(noise, CloudExponent) * CloudAmplitude;
|
2021-03-10 09:18:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
|
2021-04-22 02:53:06 +01:00
|
|
|
|
public class SectorGenerationSettings
|
|
|
|
|
|
{
|
|
|
|
|
|
public float LinkDensity = .5f;
|
|
|
|
|
|
public int ZoneCount = 128;
|
|
|
|
|
|
public int MegaCount;
|
|
|
|
|
|
public int BossCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
|
2021-04-22 02:53:06 +01:00
|
|
|
|
public class TutorialGenerationSettings
|
|
|
|
|
|
{
|
|
|
|
|
|
public string ProtagonistFaction;
|
|
|
|
|
|
public string AntagonistFaction;
|
|
|
|
|
|
public string BufferFaction;
|
|
|
|
|
|
public string[] NeutralFactions;
|
|
|
|
|
|
public string QuestFaction;
|
|
|
|
|
|
public float LinkDensity = .5f;
|
|
|
|
|
|
public int ZoneCount = 32;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName:true), JsonObject]
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public class ZoneGenerationSettings
|
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public float MassFloor = 1;
|
|
|
|
|
|
public float SunMass = 10000;
|
|
|
|
|
|
public float GasGiantMass = 2000;
|
|
|
|
|
|
public float PlanetMass = 100f;
|
|
|
|
|
|
|
|
|
|
|
|
public int SatellitePasses = 4;
|
|
|
|
|
|
public float SatelliteCreationMassFloor = 100;
|
|
|
|
|
|
public float SatelliteCreationProbability = .25f;
|
|
|
|
|
|
public float BinaryCreationProbability = .25f;
|
|
|
|
|
|
public float RosetteProbability = .25f;
|
|
|
|
|
|
|
|
|
|
|
|
public ExponentialLerp ZoneRadius;
|
|
|
|
|
|
public ExponentialLerp ZoneMass;
|
2021-03-18 00:36:34 +00:00
|
|
|
|
public ExponentialLerp SubZoneCount;
|
|
|
|
|
|
public float ZoneBoundaryRadius;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public float BeltProbability = .05f;
|
|
|
|
|
|
public float BeltMassCeiling = 500f;
|
|
|
|
|
|
|
2020-12-01 20:38:28 +00:00
|
|
|
|
public ExponentialCurve AsteroidBeltWidth;
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public ExponentialCurve AsteroidCount;
|
|
|
|
|
|
public ExponentialLerp AsteroidRotationSpeed;
|
|
|
|
|
|
|
2026-10-18 16:28:42 +02:00
|
|
|
|
// Trojan swarms (ruling trojans-ride-host-period-with-stations): the chance a planet or gas giant with a body for a parent
|
|
|
|
|
|
// carries one, each swarm's length along the orbit (turns) and radial half-width (a fraction of the host's distance), and
|
|
|
|
|
|
// the rocks round each of L4 and L5 by host distance. 0 here: a settings object built in code draws none.
|
|
|
|
|
|
public float TrojanProbability = 0f;
|
|
|
|
|
|
public float TrojanArc = .07f;
|
|
|
|
|
|
public float TrojanHalfWidth = .06f;
|
|
|
|
|
|
public ExponentialCurve TrojanCount = new ExponentialCurve { Exponent = 1f, Multiplier = .04f, Constant = 8f };
|
|
|
|
|
|
|
2026-10-22 00:44:36 +02:00
|
|
|
|
// Laned belts (rulings lanes-two-sided-visual-margin, lane-narrow): the chance a belt candidate that kept its body and has
|
|
|
|
|
|
// room on both sides carries a laned belt, and the lane's half-width in the host's body radii (1.5 by ruling). LaneProbability
|
|
|
|
|
|
// is 0 here: a settings object built in code draws no lane.
|
2026-10-21 22:42:49 +02:00
|
|
|
|
public float LaneProbability = 0f;
|
2026-10-22 00:44:36 +02:00
|
|
|
|
public float LaneBodyRadii = 1.5f;
|
2026-10-21 22:42:49 +02:00
|
|
|
|
|
2020-12-01 00:16:11 +00:00
|
|
|
|
public float ResourceDensityMinimum = .1f;
|
|
|
|
|
|
public float ResourceDensityMaximum = 1.5f;
|
2020-12-01 20:38:28 +00:00
|
|
|
|
|
|
|
|
|
|
public float SunColorSaturation = .75f;
|
|
|
|
|
|
public float SunSecondaryColorDistance = .25f;
|
|
|
|
|
|
public float SunLightSaturation = .5f;
|
|
|
|
|
|
public float SunFogTintSaturation = .5f;
|
2026-10-16 17:20:52 +02:00
|
|
|
|
// The green band no sun colour may take, as fractions of the hue circle (75 to 165 degrees: chartreuse through spring green).
|
|
|
|
|
|
public float SunHueExcludedStart = 75f / 360f;
|
|
|
|
|
|
public float SunHueExcludedEnd = 165f / 360f;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2020-12-01 20:38:28 +00:00
|
|
|
|
public ExponentialLerp GasGiantBandCount;
|
|
|
|
|
|
public float GasGiantBandColorSeparation = .25f;
|
|
|
|
|
|
public float GasGiantBandAltColorChance = .25f;
|
|
|
|
|
|
public ExponentialLerp GasGiantBandSaturation;
|
|
|
|
|
|
public ExponentialLerp GasGiantBandBrightness;
|
2021-03-10 09:18:07 +00:00
|
|
|
|
|
|
|
|
|
|
public string[] NameData;
|
2026-09-17 14:00:22 +02:00
|
|
|
|
|
|
|
|
|
|
// Non-hostile ships for hand-testing combat/targeting: belong to a galaxy faction that is
|
|
|
|
|
|
// neither the zone owner nor the zone's nearest faction, so derived hostility rules leave
|
|
|
|
|
|
// them non-hostile to the player. Zero eligible factions means none are spawned.
|
|
|
|
|
|
public int NeutralWandererCount = 2;
|
2020-12-01 00:16:11 +00:00
|
|
|
|
}
|
2020-12-10 23:20:38 +00:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName: true), JsonObject]
|
2020-12-10 23:20:38 +00:00
|
|
|
|
public class GameplaySettings
|
|
|
|
|
|
{
|
2021-03-15 11:40:46 +00:00
|
|
|
|
public EntitySettings DefaultEntitySettings;
|
2021-03-08 02:57:38 +00:00
|
|
|
|
public RarityTier[] Tiers;
|
2021-03-20 04:20:17 +00:00
|
|
|
|
public ExponentialLerp QualityPriceModifier;
|
2026-10-06 19:30:31 +02:00
|
|
|
|
// What a station pays for goods, as a fraction of their price, scaled further by the item's condition.
|
|
|
|
|
|
public float SellFraction = .5f;
|
|
|
|
|
|
// What a station charges to restore worn gear, as a fraction of the price of the wear.
|
|
|
|
|
|
public float RepairFraction = .25f;
|
|
|
|
|
|
public int StartingCredits = 15000000;
|
2021-03-22 05:22:31 +00:00
|
|
|
|
public float DurabilityQualityExponent = 2;
|
|
|
|
|
|
public float DurabilityQualityMin = 2;
|
|
|
|
|
|
public float DurabilityQualityMax = .25f;
|
|
|
|
|
|
public float ThermalQualityExponent = 2;
|
|
|
|
|
|
public float ThermalQualityMin = 2;
|
|
|
|
|
|
public float ThermalQualityMax = .25f;
|
2021-03-07 01:10:31 +00:00
|
|
|
|
public float DefaultShutdownPerformance = .25f;
|
2026-10-07 14:52:12 +02:00
|
|
|
|
// Free-floating bodies (floating items, mines): drag on a launch velocity, drag on the force-driven drift, and
|
|
|
|
|
|
// how strongly the zone force accelerates it.
|
|
|
|
|
|
public float FloatingBodyDrag = .05f;
|
|
|
|
|
|
public float FloatingBodyLaunchDrag = .2f;
|
|
|
|
|
|
public float FloatingBodyGravity = 1f;
|
2026-10-12 04:00:08 +02:00
|
|
|
|
// Loot: the chance each equipped item (the hull excepted) drops when its carrier dies, the launch speed of a
|
|
|
|
|
|
// dropped item, and how many seconds a floating item lasts.
|
|
|
|
|
|
public float LootDropProbability = .25f;
|
|
|
|
|
|
public float LootDropVelocity = 25f;
|
|
|
|
|
|
public float FloatingItemLifetime = 30f;
|
2021-03-06 02:42:19 +00:00
|
|
|
|
public float SevereHeatstrokeRiskThreshold = .25f;
|
2021-03-05 14:31:18 +00:00
|
|
|
|
public float WormholeDepth = 1000;
|
|
|
|
|
|
public float WormholeExitVelocity = 20;
|
|
|
|
|
|
public float WormholeExitRadius = 50;
|
|
|
|
|
|
public float WormholeAnimationDuration = 4;
|
|
|
|
|
|
public float WormholeExitCurveStart = .8f;
|
|
|
|
|
|
public float ThermalWearExponent = .01f;
|
2021-06-04 14:49:00 +02:00
|
|
|
|
public float DeltaTempWearExponent = .01f;
|
2021-03-05 14:31:18 +00:00
|
|
|
|
public float QualityWearExponent = 2;
|
2021-05-02 20:59:45 +01:00
|
|
|
|
public int WeaponGroupCount = 6;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
public float WarpDistance = 25;
|
|
|
|
|
|
public float DockingDistance = 25;
|
2026-10-22 16:38:17 +02:00
|
|
|
|
// Units per second one pilot gives to a ship within DockingDistance; a commodity unit or one crafted item.
|
|
|
|
|
|
public float TransferRate = 2;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public float ProductionPersonalityLerp = .05f;
|
2020-12-10 23:20:38 +00:00
|
|
|
|
public float MessageDuration = 4f;
|
|
|
|
|
|
public float TargetPersistenceDuration = 3;
|
|
|
|
|
|
public ExponentialLerp StartingGearQuality;
|
|
|
|
|
|
public float HeatRadiationExponent = 1;
|
|
|
|
|
|
public float HeatRadiationMultiplier = 1;
|
2020-12-27 22:18:22 +00:00
|
|
|
|
public float HeatConductionMultiplier = 1;
|
2021-01-27 00:05:30 +00:00
|
|
|
|
public ExponentialCurve TemperatureEmissionCurve;
|
2020-12-31 19:53:16 +00:00
|
|
|
|
public float HeatstrokeTemperature = 330;
|
|
|
|
|
|
public float HeatstrokeMultiplier = .00001f;
|
|
|
|
|
|
public float HeatstrokeExponent = 2;
|
|
|
|
|
|
public float HeatstrokeRecoverySpeed = .2f;
|
|
|
|
|
|
public float HeatstrokeControlLimit = .75f;
|
2021-04-10 01:47:16 +01:00
|
|
|
|
public float HypothermiaTemperature = 273;
|
|
|
|
|
|
public float HypothermiaMultiplier = .00001f;
|
|
|
|
|
|
public float HypothermiaExponent = 2;
|
|
|
|
|
|
public float HypothermiaRecoverySpeed = .2f;
|
|
|
|
|
|
public float HypothermiaControlLimit = .75f;
|
2021-01-10 03:59:47 +00:00
|
|
|
|
public float LockIndicatorNoiseAmplitude = 50f;
|
|
|
|
|
|
public ExponentialLerp LockIndicatorFrequency;
|
|
|
|
|
|
public ExponentialLerp LockSpinSpeed;
|
2021-01-11 02:56:37 +00:00
|
|
|
|
public float TorqueMultiplier;
|
2021-01-25 05:53:36 +00:00
|
|
|
|
public float VisibilityDecay;
|
2026-10-11 18:25:57 +02:00
|
|
|
|
// Seconds a reveal's bearing keeps a ship Detected after its last act with no track (Entity.ContactOf).
|
|
|
|
|
|
public float BearingMemory = 6;
|
2021-02-11 03:14:20 +00:00
|
|
|
|
public float TargetInfoDecay;
|
|
|
|
|
|
public float TargetDetectionInfoThreshold;
|
2026-10-11 18:25:57 +02:00
|
|
|
|
// Also the Identified threshold: the track level at which a ship's hull class, and with it its layout, is known.
|
2021-02-11 03:14:20 +00:00
|
|
|
|
public float TargetGearInfoThreshold;
|
2021-01-27 16:14:41 +00:00
|
|
|
|
public float ConvergenceMinimumDistance;
|
Delete HardpointTransforms; mount direction and arc become sim data
Entity.HardpointTransforms was written only by Unity (EntityInstance.cs),
so the simulation's notion of where a gun points was a readback from a
renderer that never runs headless -- Combat.cs threw KeyNotFoundException
on the first combat tick outside Unity. Deletes the field, its writer, and
the readback branch in Behavior.Direction, leaving the item-rotation path
(the same convention reaction thrusters use, R6) as the only source of
mount direction.
Adds FireControl (ServerShared), a static class owning whether a weapon
bears on a point: MountDirection (planar, from ItemRotation), ArcFor (the
per-hardpoint HardpointData.FiringArc override, falling back to the new
GameplaySettings.FiringArc default of 120), and InArc (the planar dot-cone
test, R7 -- target height never enters it, and an arc of 360+ passes
unconditionally so a turret hardpoint needs no new type, just a number).
Combat.cs and TurretController.cs now gate AI fire through InArc instead
of the old hardcoded 0.99 dot-product test against a live Unity transform.
Settings.cs drops AgentFiringMinDot, which was declared and read by
nothing.
docs/fire-control-cut.md, Cut 1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 07:37:52 +02:00
|
|
|
|
public float FiringArc = 120;
|
2026-09-19 13:02:05 +02:00
|
|
|
|
// Cut 2 (docs/fire-control-cut.md, Q4): what an entity with no working targeting system fires with --
|
|
|
|
|
|
// the ceiling FireControl.Accuracy falls back to (Resolution 1, Precision 0 alongside it). Authored low
|
|
|
|
|
|
// on purpose ("really, really bad," operator 2026-09-19): .05 against the two catalog designs' own
|
|
|
|
|
|
// Accuracy ranges (the authoring spec this cut produces proposes .45-.6 for the 1-cell design and
|
|
|
|
|
|
// .65-.85 for the 2-cell one) leaves unaided fire capable of hitting something close, slow and
|
|
|
|
|
|
// unaware, and little else. One authored setting, easy to find and turn -- the operator rules the real
|
|
|
|
|
|
// figure in play.
|
|
|
|
|
|
public float UnaidedAccuracy = .05f;
|
Fire control Cut 5: close the rules that landed on one path and not its twin
Soul's pass over the whole campaign confirmed eleven findings. Seven were code
defects of one shape -- a rule implemented on one path and left off the path
beside it -- and this is all seven.
5.1 Tracking falls back to GameplaySettings.UnaidedTracking (new, 10) instead of
zero, and Commit drops the zero branch that turned a Tracking-less shooter
into a hard wall. Unaided fire was meant to be really, really bad; it was
334 shots and no hits against a target drifting at 5 u/s.
5.2 A shot the shield cannot absorb now breaks it. The decision is frozen into
ShotOutcome.ShieldBroken at commit and performed in Apply, so a shield that
recharges mid-flight cannot retroactively survive. Splash already did this;
the discrete roll never did, which made the whole shield-break mechanic
unreachable for every weapon in the catalog.
5.3 ConstantWeapon gates on ArcAllowsFire alongside StanceAllowsFire. A
side-mounted beam was firing forward.
5.4 The point-blank bearing case moves out of Weapon.ArcAllowsFire and into
InArc, which used to normalize the zero vector into NaN. The trigger said
fire and the probability said impossible.
5.5 A destroyed item drops out of IsRevealed's ranking, so Precision stops
concentrating hits onto a dead subsystem's footprint.
5.6 Zone subscribes Entity.Death and removes the corpse itself. That removal
lived only in Unity's loot-drop subscription, so headless nothing ever left
the zone, shots landed on corpses and no fight could end.
5.7 PendingShot drops PredictedIntercept and FlightTime, written and read
nowhere.
208 tests pass (197 plus eleven new).
Known defect, recorded rather than hidden: the committed mutation harness is
unreliable. Across two runs it failed to restore FireControl.cs and Weapon.cs,
leaving live mutations in the working tree -- including its own 5.1 mutation,
which is how a green suite briefly reported two failures. Its verdicts are
therefore evidence only where re-run from a verified-clean tree. Two anchors
(Zone.cs's ObserveAdd line, Weapon.cs's InArc return) fail to match at all, and
5.3's ConstantWeaponObeysArc survives its own mutation, so that rule is written
but not pinned. Cut 5b owns the repair; nothing here is trusted on the harness's
word, and the suite result above was taken by hand from a hash-verified tree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 16:56:40 +02:00
|
|
|
|
// Cut 5 (docs/fire-control-cut.md, 5.1, Soul finding 3): the unaided fallback for Tracking, alongside
|
|
|
|
|
|
// UnaidedAccuracy above -- an entity with no working targeting system used to fall back to Tracking 0,
|
|
|
|
|
|
// which Commit turned into a hard wall (any nonzero deviation was an automatic miss). Ten world units of
|
|
|
|
|
|
// fire-time-projection deviation forgiveness is the first guess and the operator's knob, the same shape
|
|
|
|
|
|
// as UnaidedAccuracy: authored deliberately bad, not authored broken.
|
|
|
|
|
|
public float UnaidedTracking = 10f;
|
Cut 6d: the dart-throw kernel replaces the coin-flip landing rule
FireControl.Commit used to place a hit with a coin flip between exactly
the aimed item and a uniform-random hull cell -- no spatial term, so a
near-miss on a stern item was as likely to land in the bow as the stern.
One Gaussian kernel, in hull-schematic cell units, now decides both
halves of "where will this shot go": w(cell) = exp(-d^2/2*sigma^2) over
every occupied cell, sigma = 1/Precision. HitProbability folds the
kernel's on-hull mass share (pOnHull) into PBase at fire time (R10/Q6
unaffected); Commit draws the landing cell from the same weights. A shot
that passes the roll always lands on metal -- the off-hull chance is
priced into that one roll, never resolved as a second miss stage. The
uniform-random branch is deleted outright, not demoted.
Precision now feeds every shot's pOnHull, aimed or not, so its unaided
fallback (FireControl.Precision) reads GameplaySettings.UnaidedPrecision
instead of a bare 0 -- the same shape as the existing UnaidedAccuracy/
UnaidedTracking floors. pOnHull is saturated: the discrete sum over-
estimates the continuous kernel's integral once sigma drops below about
one cell, and a mass share cannot exceed the whole kernel.
Existing fixtures across FireAuthorityTests, FireControlCut4/5/6Tests and
TargetingSystemTests authored Precision as 0 (or relied on the old 0
fallback) purely as a don't-care value under the coin-flip rule, where it
only gated the aimed-item branch. Under the kernel it drives every shot's
sigma, so those fixtures are re-authored to keep pOnHull near its
ceiling and stay pinned on what they actually test.
mutation_tests_fire_control_cut3.sh's two anchors into HitProbability's
return line and the deleted coin-flip branch are updated to the
equivalent lines/mutations on the new code.
2026-09-19 21:37:39 +02:00
|
|
|
|
// Cut 6d (docs/fire-control-cut.md): the unaided fallback for Precision, alongside UnaidedAccuracy and
|
|
|
|
|
|
// UnaidedTracking above -- FireControl.Precision falls back to this the same way it already falls back to
|
|
|
|
|
|
// UnaidedAccuracy/UnaidedTracking. Precision is now a grouping tightness (FireControl.Sigma = 1/Precision,
|
|
|
|
|
|
// in hull-schematic cell units), not the old coin-flip probability, so the unaided floor has to be
|
Delete the aether drive: behaviour, union 12, hardpoint type, aggregates, settings, presenters, prefab
AetherDriveData and AetherDrive, Union(12) (now a retired-do-not-reuse comment, as 26 is),
HardpointType.AetherDrive (last member, nothing shifts), Ship's drive sets, aggregates and
Axis write, the five request-field rows, GameplaySettings Aether multipliers, ShipInstance's
drive particles, SchematicDisplay's RPM display and AetherDriveUi, the undock refusal's drive
clause, the drive prefab and material, and AetherDb's drive roles and brownout row. The
design is kept at parked/aether-drive.
Adds EveryShippedShipHullHasATopSpeed. ARPG.unity still holds stale serialized references to
the removed SchematicDisplay fields and the RPM Display object; the next commit removes them.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 14:04:28 +02:00
|
|
|
|
// authored on that scale. .3 -> sigma 3.33 cells: against the live catalog's own hulls (Longinus 6x17,
|
Cut 6d: the dart-throw kernel replaces the coin-flip landing rule
FireControl.Commit used to place a hit with a coin flip between exactly
the aimed item and a uniform-random hull cell -- no spatial term, so a
near-miss on a stern item was as likely to land in the bow as the stern.
One Gaussian kernel, in hull-schematic cell units, now decides both
halves of "where will this shot go": w(cell) = exp(-d^2/2*sigma^2) over
every occupied cell, sigma = 1/Precision. HitProbability folds the
kernel's on-hull mass share (pOnHull) into PBase at fire time (R10/Q6
unaffected); Commit draws the landing cell from the same weights. A shot
that passes the roll always lands on metal -- the off-hull chance is
priced into that one roll, never resolved as a second miss stage. The
uniform-random branch is deleted outright, not demoted.
Precision now feeds every shot's pOnHull, aimed or not, so its unaided
fallback (FireControl.Precision) reads GameplaySettings.UnaidedPrecision
instead of a bare 0 -- the same shape as the existing UnaidedAccuracy/
UnaidedTracking floors. pOnHull is saturated: the discrete sum over-
estimates the continuous kernel's integral once sigma drops below about
one cell, and a mass share cannot exceed the whole kernel.
Existing fixtures across FireAuthorityTests, FireControlCut4/5/6Tests and
TargetingSystemTests authored Precision as 0 (or relied on the old 0
fallback) purely as a don't-care value under the coin-flip rule, where it
only gated the aimed-item branch. Under the kernel it drives every shot's
sigma, so those fixtures are re-authored to keep pOnHull near its
ceiling and stay pinned on what they actually test.
mutation_tests_fire_control_cut3.sh's two anchors into HitProbability's
return line and the deleted coin-flip branch are updated to the
equivalent lines/mutations on the new code.
2026-09-19 21:37:39 +02:00
|
|
|
|
// Zenith 12x12, Turret 8x8) that puts pOnHull at the hull's own centre of mass around .5-.84 -- broadly
|
|
|
|
|
|
// sprayed across the whole silhouette (sigma is a large fraction of the hull's own width) while still
|
|
|
|
|
|
// landing on the ship more often than not. A tighter floor (e.g. .1, sigma 10) was tried first and
|
|
|
|
|
|
// rejected: it drove pOnHull for the same hulls down to .08-.18, reading as "can't hit the broad side of a
|
|
|
|
|
|
// barn" rather than "sprays the silhouette." First guess, the same deliberately-bad shape as its two
|
|
|
|
|
|
// siblings; the operator rules the real figure in play.
|
|
|
|
|
|
public float UnaidedPrecision = .3f;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
public float AgentRangeExponent = .25f;
|
|
|
|
|
|
public float AgentForwardLerp = .5f;
|
|
|
|
|
|
public float AgentMaxForwardDistance = 50;
|
Fire control Cut 3: hit authority moves to FireControl
Deletes the Unity physics hit path (HullCollider.Hit/Splash, and the
raycast/shield/SendHit blocks in Projectile, GuidedProjectile, Laser and
Lightning) and replaces it with a single owner in the same cut: FireControl
now decides whether a shot hits, Zone owns the pending-shot lifecycle, and
Entity.DamageSchematic/ApplyHit (moved verbatim from EntityInstance) apply the
result. Presentation subscribes to Zone.ShotCommitted/ShotResolved and applies
nothing.
FireControl.HitProbability is the pure targeting solution (Accuracy * pSensor
* pSpread, gated by detection/range/lock/arc). FireControl.Fire freezes the
weapon's payload and the shooter's resolved targeting stats at the instant the
trigger is pulled (Q6), computes the predicted intercept through the one
shared PredictedIntercept function (CombatState now calls the same function
instead of duplicating first_order_intercept), and queues a PendingShot.
FireControl.Step commits each shot's outcome at ArrivalTime - CommitHorizon --
deviation from the predicted intercept, measured once, live, at that instant
-- and applies it at ArrivalTime. A shot whose flight is shorter than the
horizon commits and resolves in the same tick it fires. Rolls draw from the
shooter's own ItemManager.Random (Q5, seeded and reproducible); an out-of-arc
or otherwise gated shot draws nothing.
Player fire is arc-gated through the same predicate AI and turret fire use
(Weapon.ArcAllowsFire, checked in InstantWeapon.Trigger -- the one point every
shooter's trigger passes through), closing Q2.
Adds GameplaySettings.CommitHorizon, SchematicCellSize and
AgentMinHitProbability (first guesses; the headless suite is the tuning
harness, operator play smoke is the arbiter).
FORK reported, not worked around silently: HullCollider.SendHit/SendSplash
cannot be deleted yet without breaking ConstantLaser.cs, ConstantLightning.cs,
ConstantParticleWeapon.cs, HitscanEffect.cs and Mine.cs, which still call them
from their own live Physics queries -- that's Cut 4's migration. They fire
into the void today: nothing subscribes to Hit/Splash any more for the four
weapon kinds this cut owns.
tests/Aetheria.Shared.Tests/FireAuthorityTests.cs pins the roll's seeding, the
gate-consumes-no-draw rule, resolve-on-arrival, the commit horizon and its
evasion window, short-flight degradation, the frozen-payload snapshot, aimed
hits, the item-then-hull damage order, the planar penetration march and the
shield-absorbs branch. FireControlTests.cs and InputCapacitorTests.cs are
updated for the new AI gate and OnFire(int) signature.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 14:07:07 +02:00
|
|
|
|
|
|
|
|
|
|
// Cut 3 (docs/fire-control-cut.md): first guesses: the headless fixture is the tuning harness, the
|
|
|
|
|
|
// operator smoke is the arbiter (§ Risks).
|
|
|
|
|
|
//
|
|
|
|
|
|
// How long before impact a shot's outcome commits (R4). Deviation counts up to this horizon; after it
|
|
|
|
|
|
// the result is frozen and the rest of the flight is pure choreography.
|
|
|
|
|
|
public float CommitHorizon = .5f;
|
|
|
|
|
|
|
Evasion term: reachable spread from the thrust and turn envelope, realised by changes of vector
Every hit price gains one factor, PDeviation(Evasion, Tracking): how far the target can
and does move off the line of fire within SolutionWindow (0.75 s). Capability is Reach, an
eight-face closed form over the ship's ManoeuvreEnvelope (summed from what each live
thruster and aether drive reports with its own Execute arithmetic, read live: a thruster's
Thrust property is stale until it fires, which is why the Djinni moved 1.6 times its stats,
M25). Behaviour is ManoeuvreTrack, observed once per Entity.Update from the measured
acceleration; a steady burn, coasting and a dither much faster than the window do not
evade, and sideways speed alone does not (ruling evasion-speed). The commit price adds the
term at any flight time, so an instant weapon feels a jinking target. Forecast owns the
term for HitProbability and Inspect, which gain Evasion and PEvasion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:48:27 +02:00
|
|
|
|
// The window of fire control's solution: how far ahead a target's reach counts (Reach, Evasion) and the time
|
|
|
|
|
|
// constant of the manoeuvre track that observes it. A fire-control constant, not a weapon or missile stat. First
|
|
|
|
|
|
// guess; the operator rules the real figure in play.
|
|
|
|
|
|
public float SolutionWindow = .75f;
|
|
|
|
|
|
|
Fire control Cut 3: hit authority moves to FireControl
Deletes the Unity physics hit path (HullCollider.Hit/Splash, and the
raycast/shield/SendHit blocks in Projectile, GuidedProjectile, Laser and
Lightning) and replaces it with a single owner in the same cut: FireControl
now decides whether a shot hits, Zone owns the pending-shot lifecycle, and
Entity.DamageSchematic/ApplyHit (moved verbatim from EntityInstance) apply the
result. Presentation subscribes to Zone.ShotCommitted/ShotResolved and applies
nothing.
FireControl.HitProbability is the pure targeting solution (Accuracy * pSensor
* pSpread, gated by detection/range/lock/arc). FireControl.Fire freezes the
weapon's payload and the shooter's resolved targeting stats at the instant the
trigger is pulled (Q6), computes the predicted intercept through the one
shared PredictedIntercept function (CombatState now calls the same function
instead of duplicating first_order_intercept), and queues a PendingShot.
FireControl.Step commits each shot's outcome at ArrivalTime - CommitHorizon --
deviation from the predicted intercept, measured once, live, at that instant
-- and applies it at ArrivalTime. A shot whose flight is shorter than the
horizon commits and resolves in the same tick it fires. Rolls draw from the
shooter's own ItemManager.Random (Q5, seeded and reproducible); an out-of-arc
or otherwise gated shot draws nothing.
Player fire is arc-gated through the same predicate AI and turret fire use
(Weapon.ArcAllowsFire, checked in InstantWeapon.Trigger -- the one point every
shooter's trigger passes through), closing Q2.
Adds GameplaySettings.CommitHorizon, SchematicCellSize and
AgentMinHitProbability (first guesses; the headless suite is the tuning
harness, operator play smoke is the arbiter).
FORK reported, not worked around silently: HullCollider.SendHit/SendSplash
cannot be deleted yet without breaking ConstantLaser.cs, ConstantLightning.cs,
ConstantParticleWeapon.cs, HitscanEffect.cs and Mine.cs, which still call them
from their own live Physics queries -- that's Cut 4's migration. They fire
into the void today: nothing subscribes to Hit/Splash any more for the four
weapon kinds this cut owns.
tests/Aetheria.Shared.Tests/FireAuthorityTests.cs pins the roll's seeding, the
gate-consumes-no-draw rule, resolve-on-arrival, the commit horizon and its
evasion window, short-flight degradation, the frozen-payload snapshot, aimed
hits, the item-then-hull damage order, the planar penetration march and the
shield-absorbs branch. FireControlTests.cs and InputCapacitorTests.cs are
updated for the new AI gate and OnFire(int) signature.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 14:07:07 +02:00
|
|
|
|
// World units per hull-schematic cell, used only by FireControl.HitProbability's angular-size term
|
|
|
|
|
|
// (pSpread) to turn a hull's cell footprint into a real-world silhouette size at range.
|
|
|
|
|
|
public float SchematicCellSize = 2f;
|
|
|
|
|
|
|
2026-10-12 18:28:29 +02:00
|
|
|
|
// Restitution of a hull striking a hull (Contacts.Step): the speed at which a pair separates along the contact
|
|
|
|
|
|
// normal is this times the speed at which it closed. 0 is perfectly inelastic, 1 perfectly elastic.
|
|
|
|
|
|
public float ContactRestitution = .5f;
|
|
|
|
|
|
|
2026-10-16 02:35:07 +02:00
|
|
|
|
// Heights above the field of the ship plane, the orbital layer (stations, turrets: every OrbitalEntity) and the floater
|
|
|
|
|
|
// layer (loot, mines): orbitals above ships and floaters below them, so no ship ever touches either (ruling
|
|
|
|
|
|
// aetheria-gravity:orbitals-above-floaters-below).
|
|
|
|
|
|
public float ShipLayerHeight = 3f;
|
|
|
|
|
|
public float OrbitalLayerHeight = 15f;
|
|
|
|
|
|
public float FloaterLayerHeight = 0f;
|
|
|
|
|
|
|
Fire control Cut 3: hit authority moves to FireControl
Deletes the Unity physics hit path (HullCollider.Hit/Splash, and the
raycast/shield/SendHit blocks in Projectile, GuidedProjectile, Laser and
Lightning) and replaces it with a single owner in the same cut: FireControl
now decides whether a shot hits, Zone owns the pending-shot lifecycle, and
Entity.DamageSchematic/ApplyHit (moved verbatim from EntityInstance) apply the
result. Presentation subscribes to Zone.ShotCommitted/ShotResolved and applies
nothing.
FireControl.HitProbability is the pure targeting solution (Accuracy * pSensor
* pSpread, gated by detection/range/lock/arc). FireControl.Fire freezes the
weapon's payload and the shooter's resolved targeting stats at the instant the
trigger is pulled (Q6), computes the predicted intercept through the one
shared PredictedIntercept function (CombatState now calls the same function
instead of duplicating first_order_intercept), and queues a PendingShot.
FireControl.Step commits each shot's outcome at ArrivalTime - CommitHorizon --
deviation from the predicted intercept, measured once, live, at that instant
-- and applies it at ArrivalTime. A shot whose flight is shorter than the
horizon commits and resolves in the same tick it fires. Rolls draw from the
shooter's own ItemManager.Random (Q5, seeded and reproducible); an out-of-arc
or otherwise gated shot draws nothing.
Player fire is arc-gated through the same predicate AI and turret fire use
(Weapon.ArcAllowsFire, checked in InstantWeapon.Trigger -- the one point every
shooter's trigger passes through), closing Q2.
Adds GameplaySettings.CommitHorizon, SchematicCellSize and
AgentMinHitProbability (first guesses; the headless suite is the tuning
harness, operator play smoke is the arbiter).
FORK reported, not worked around silently: HullCollider.SendHit/SendSplash
cannot be deleted yet without breaking ConstantLaser.cs, ConstantLightning.cs,
ConstantParticleWeapon.cs, HitscanEffect.cs and Mine.cs, which still call them
from their own live Physics queries -- that's Cut 4's migration. They fire
into the void today: nothing subscribes to Hit/Splash any more for the four
weapon kinds this cut owns.
tests/Aetheria.Shared.Tests/FireAuthorityTests.cs pins the roll's seeding, the
gate-consumes-no-draw rule, resolve-on-arrival, the commit horizon and its
evasion window, short-flight degradation, the frozen-payload snapshot, aimed
hits, the item-then-hull damage order, the planar penetration march and the
shield-absorbs branch. FireControlTests.cs and InputCapacitorTests.cs are
updated for the new AI gate and OnFire(int) signature.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 14:07:07 +02:00
|
|
|
|
// The floor an AI's own predicted hit probability (FireControl.HitProbability) must clear before it counts
|
|
|
|
|
|
// a firing solution worth taking (Combat.cs, TurretController.cs). Player fire is gated on arc alone
|
|
|
|
|
|
// (Weapon.ArcAllowsFire, Q2) -- this threshold is an AI fire-discipline heuristic, not part of the roll.
|
|
|
|
|
|
public float AgentMinHitProbability = .2f;
|
2026-09-19 15:16:57 +02:00
|
|
|
|
|
|
|
|
|
|
// Cut 4 (docs/fire-control-cut.md): how often a continuous weapon (ConstantWeapon) rolls a discrete
|
|
|
|
|
|
// outcome for Damage * this interval, through the same FireControl.Fire/Step pair a discrete shot uses --
|
|
|
|
|
|
// a beam is a sequence of rolls, not a continuous truth. First guess; the headless fixture is the tuning
|
|
|
|
|
|
// harness, the operator smoke is the arbiter, same as Cut 3's other first guesses.
|
|
|
|
|
|
public float BeamResolveInterval = .25f;
|
2021-03-08 02:57:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Serializable, MessagePackObject(keyAsPropertyName: true), JsonObject]
|
2021-03-08 02:57:38 +00:00
|
|
|
|
public class RarityTier
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Name;
|
|
|
|
|
|
public float Quality;
|
|
|
|
|
|
public float3 Color;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
}
|