Table of Contents

Class AICombatDecision

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

The single combat decision shared by every attacking state.

public static class AICombatDecision
Inheritance
AICombatDecision
Inherited Members

Remarks

Melee, ranged, caster, healer, defender and rogue states previously each carried their own near-identical TryAttack override — five copies of "am I too close? can I cast? do I walk in?" that drifted apart from one another and could only be verified by playing the game. They now all funnel through Plan(in AICombatContext) and differ purely in the numbers they feed it and in what they do with the resulting intent.

Because this is a pure function over plain floats, an archetype asset's behaviour is directly assertable in an EditMode test — see AICombatDecisionTests and AIArchetypeAssetTests.

Fields

ENGAGE_SLACK

Multiplier applied to the engagement distance before the NPC bothers closing in. Without the slack the NPC oscillates between "one centimetre too far" and "stop".

public const float ENGAGE_SLACK = 1.1

Field Value

float

RANGE_APPROACH_FACTOR

Fraction of an ability's range the NPC actually walks to. Stopping exactly at maximum range means the first step the target takes puts the NPC out of range again.

public const float RANGE_APPROACH_FACTOR = 0.9

Field Value

float

RANGE_HYSTERESIS

How far past its ability range a target may drift before an already-attacking NPC gives up and closes again.

public const float RANGE_HYSTERESIS = 1.1

Field Value

float

Remarks

Without this the decision at the range boundary is a bare distance <= range, and a target strafing around that boundary flips the NPC between Attack and CloseDistance on alternating ticks. Each flip toggles NavMeshAgent.isStopped, and because the agent has acceleration and braking it never reaches speed in either direction — the NPC visibly shudders in place instead of either fighting or chasing.

Ten percent is enough to absorb a strafing player without letting the NPC attack from meaningfully outside its stated range.

Methods

Plan(in AICombatContext)

Decides what the NPC should do about its target this tick.

public static AICombatPlan Plan(in AICombatContext context)

Parameters

context AICombatContext

The measured combat situation.

Returns

AICombatPlan

The intent plus the distance the movement intents should aim for.

ResolveApproachDistance(in AICombatContext, float)

Where to stop when walking an out-of-range ability into range.

public static float ResolveApproachDistance(in AICombatContext context, float engageDistance)

Parameters

context AICombatContext

The measured combat situation.

engageDistance float

The archetype's engagement distance.

Returns

float

The distance from the target at which to stop moving.

Remarks

Approaches to a fraction of the ability's range so a moving target does not immediately step back out, but never closer than the archetype's engagement distance — a caster with a 30 m nuke and a 20 m preferred distance stops at 20, not at 27. A melee archetype (no preferred distance) is allowed to close all the way.

ResolveEngageDistance(in AICombatContext)

public static float ResolveEngageDistance(in AICombatContext context)

Parameters

context AICombatContext

Returns

float

ResolveSpacing(float, float, float, out float, out float)

The distance this archetype wants to sit at: its preferred distance, or melee reach when it has none.

public static void ResolveSpacing(float preferredDistance, float minComfortDistance, float maxOffensiveReach, out float effectivePreferred, out float effectiveComfort)

Parameters

preferredDistance float

The state's preferred distance.

minComfortDistance float

The state's comfort distance.

maxOffensiveReach float

The NPC's longest offensive reach, 0 if none.

effectivePreferred float

The preferred distance to plan with.

effectiveComfort float

The comfort distance to plan with.

Remarks

The spacing on a state asset is a hope, not a fact: the Caster archetype prefers 22 m and backs away inside 10 m, and the orc mage that uses it knows one ability that reaches 1.25 m. Taken literally that spacing produced an NPC which kept its distance forever and never attacked — the "constantly retreats to cast range" report.

The preferred distance is capped at the longest offensive reach, and a comfort distance the NPC cannot attack from is dropped: backing away to a range you cannot hit from is not kiting. An NPC that knows no abilities keeps its spacing as authored.