Files
Project-M/Assets/_Project/Scripts/Simulation/Economy/BaseFieldSpawner.cs
T
kronic e1ed08a803 Economy: base-local mining loop (mine at base, any attack harvests, scheduled sieges)
Consolidate the divorced combat + economy halves into one base-local loop. BaseFieldSpawnSystem tops up RegionTag{Base} Ore nodes around the plot; harvest routes Base->shared ledger and Expedition/untagged->personal inventory for BOTH the projectile (ResourceHarvestSystem) and melee (MeleeComboSystem server-only block, writes Remaining back for VFX). Activate the reserved Schedule source in ThreatDirectorSystem so base sieges arm WITHOUT an expedition trip (the loop-closer: previously zero waves ever attacked a base-only player). Region-filter the ExpeditionFieldSystem teardown so it no longer wipes the permanent base field. HudSystem shows phase-aware loop copy. See DR-031.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 14:59:51 -07:00

47 lines
2.5 KiB
C#

using Unity.Entities;
namespace ProjectM.Simulation
{
/// <summary>
/// Baked singleton describing the HOME-BASE mining field: a ring of harvestable resource nodes scattered
/// around the base so the gather -> build -> survive loop lives on ONE screen (no expedition trip required).
/// DISTINCT from <see cref="ResourceFieldSpawner"/> (the expedition field) so the two never collide on a
/// GetSingleton. <see cref="ProjectM.Server.BaseFieldSpawnSystem"/> keeps the live RegionTag{Base} node count
/// topped up to <see cref="TargetCount"/> on a tick cadence; nodes scatter UNIFORMLY-IN-RADIUS in the annulus
/// [<see cref="InnerRadius"/>, <see cref="OuterRadius"/>] around BaseGridMath.PlotCenter (inner clears the
/// square build plot + spawn ring, outer stays inside the walkable boundary ring) and are overridden to
/// RegionTag{Base} + ResourceId.Ore (the sole build currency, kept legible — never the expedition's
/// Aether/Ore/Biomass round-robin). Place ONE authoring in the gameplay subscene.
/// </summary>
public struct BaseFieldSpawner : IComponentData
{
/// <summary>Baked resource-node ghost prefab to instantiate (reuses the expedition node prefab).</summary>
public Entity Prefab;
/// <summary>Desired live base-node count; the system refills toward this each respawn pass.</summary>
public int TargetCount;
/// <summary>Inner scatter radius (world units) from the plot center — must clear the build plot + spawn ring.</summary>
public float InnerRadius;
/// <summary>Outer scatter radius (world units) — must stay inside the boundary ring so nodes are reachable.</summary>
public float OuterRadius;
/// <summary>Server ticks between top-up passes (a depleted field refills toward TargetCount on this cadence).</summary>
public int RespawnIntervalTicks;
}
/// <summary>
/// Server-only runtime state for <see cref="ProjectM.Server.BaseFieldSpawnSystem"/>, baked beside
/// <see cref="BaseFieldSpawner"/>. NOT replicated. <see cref="Epoch"/> seeds the per-node scatter RNG
/// (monotonic, so a top-up never repeats a layout); <see cref="NextSpawnTick"/> gates the cadence (wrap-safe
/// via TickUtil.NonZero + NetworkTick.IsNewerThan, never raw uint). NextSpawnTick == 0 means "fire now" so the
/// first pass seeds the field without waiting for a tick that never comes.
/// </summary>
public struct BaseFieldRuntime : IComponentData
{
public int Epoch;
public uint NextSpawnTick;
}
}