Add targeting subsystem, reveal rule and selection slot (fire control Cut 2)
TargetingSystem is required interior Tool gear: Accuracy/Resolution/ Precision/Tracking are PerformanceStats reached through the usual Evaluate path, so lot quality, wear, heat and PowerSupply all apply (a starved system rolls worse, never switches off). FireControl.Accuracy/ Resolution/Precision fall back to GameplaySettings.UnaidedAccuracy (new, authored low per Q4) whenever an entity has no targeting system or its own is destroyed/disabled. FireControl.IsRevealed derives R5's reveal rule from EntityInfoGathered: non-hull equipment ranks hardpoint-mounted first, then by size, and reveals between TargetArmorInfoThreshold and TargetGearInfoThreshold -- the first code to read either setting. Entity.TargetItem/ TrySelectTargetItem/ResolvedTargetItem give both the player and AI one shared, revoke-on-decay aim-point slot with a single writer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3ea29acc3f
commit
c4a57a8df0
6 changed files with 191 additions and 2 deletions
|
|
@ -2,13 +2,16 @@
|
|||
* 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.Linq;
|
||||
using CultMath;
|
||||
using static CultMath.math;
|
||||
|
||||
// Cut 1 (docs/fire-control-cut.md): geometry only. Whether a weapon bears on a point is decided here and
|
||||
// Cut 1 (docs/fire-control-cut.md): geometry -- whether a weapon bears on a point is decided here and
|
||||
// nowhere else -- no prefab, transform, ArticulationPoint or renderer may influence it (R6, R7). Mount
|
||||
// direction and arc are both derived per read from catalog data and the item's authored rotation; neither
|
||||
// is ever stored on the entity.
|
||||
// Cut 2 adds the reveal rule (R5) and the resolved targeting-system stats an entity fires with, both
|
||||
// likewise derived on every read and never cached.
|
||||
public static class FireControl
|
||||
{
|
||||
// The planar unit vector a hardpoint's weapon points along, derived solely from the item's authored
|
||||
|
|
@ -40,4 +43,61 @@ public static class FireControl
|
|||
var planarTarget = normalize(float3(toTarget.x, 0, toTarget.z));
|
||||
return dot(MountDirection(weapon), planarTarget) >= cos(radians(arc / 2f));
|
||||
}
|
||||
|
||||
// Cut 2, R5: whether `observer` has resolved `item` (which must belong to some entity in the zone) well
|
||||
// enough to aim at it. Derived fresh from EntityInfoGathered on every call -- nothing caches a reveal
|
||||
// result, so decay drops it the moment info falls back below tier, with no clearing loop anywhere.
|
||||
//
|
||||
// Ranking: the target's own non-hull equipment, hardpoint-mounted gear first (the big obvious things),
|
||||
// then by size descending, ties broken by equipment order (OrderByDescending is a stable sort, so this
|
||||
// needs no explicit tie-break key). Item i of N reveals once info crosses
|
||||
// lerp(TargetArmorInfoThreshold, TargetGearInfoThreshold, i / max(1, N - 1)) -- the first item to reveal
|
||||
// does so at the armor tier, the last at the gear tier.
|
||||
public static bool IsRevealed(Entity observer, EquippedItem item)
|
||||
{
|
||||
var target = item.Entity;
|
||||
var ranked = target.Equipment
|
||||
.Where(e => e.Data.HardpointType != HardpointType.Hull)
|
||||
.OrderByDescending(e => e.Data.HardpointType != HardpointType.Tool)
|
||||
.ThenByDescending(e => e.Data.Shape.Coordinates.Length)
|
||||
.ToList();
|
||||
var index = ranked.IndexOf(item);
|
||||
if (index < 0) return false; // the hull itself, or an item that is no longer on this target
|
||||
|
||||
var settings = observer.ItemManager.GameplaySettings;
|
||||
var info = observer.EntityInfoGathered.TryGetValue(target, out var gathered) ? gathered : 0f;
|
||||
var tier = lerp(settings.TargetArmorInfoThreshold, settings.TargetGearInfoThreshold,
|
||||
(float) index / max(1, ranked.Count - 1));
|
||||
return info >= tier;
|
||||
}
|
||||
|
||||
// Cut 2, Q4: the stats an entity actually fires with. A working targeting system (equipped, online --
|
||||
// not destroyed, not shut down) supplies its own resolved stats; anything else falls back to the
|
||||
// authored unaided figures, which make aiming without one a last resort rather than an alternative.
|
||||
// Cut 3's roll is the only planned reader.
|
||||
public static float Accuracy(Entity entity)
|
||||
{
|
||||
var system = entity.GetBehavior<TargetingSystem>();
|
||||
return system != null && system.Item.Active.Value
|
||||
? system.Accuracy
|
||||
: entity.ItemManager.GameplaySettings.UnaidedAccuracy;
|
||||
}
|
||||
|
||||
public static float Resolution(Entity entity)
|
||||
{
|
||||
var system = entity.GetBehavior<TargetingSystem>();
|
||||
return system != null && system.Item.Active.Value ? system.Resolution : 1f;
|
||||
}
|
||||
|
||||
public static float Precision(Entity entity)
|
||||
{
|
||||
var system = entity.GetBehavior<TargetingSystem>();
|
||||
return system != null && system.Item.Active.Value ? system.Precision : 0f;
|
||||
}
|
||||
|
||||
public static float Tracking(Entity entity)
|
||||
{
|
||||
var system = entity.GetBehavior<TargetingSystem>();
|
||||
return system != null && system.Item.Active.Value ? system.Tracking : 0f;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue