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)

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

public static float ResolveEngageDistance(in AICombatContext context)

Parameters

context AICombatContext

The measured combat situation.

Returns

float

A strictly positive engagement distance.