Files
core2026/docs/architecture/legacy-engine-general.md
T

3.8 KiB

Legacy General Model and Action Stack

This document captures how General aggregates modifiers, computes stats, and exposes trigger hooks. The main reference is legacy/hwe/sammo/General.php.

Construction and Core State

  • General builds from raw DB rows (general, city, nation, rank, access log).
  • last_turn is parsed into LastTurn, and a separate resultTurn is maintained for updates.
  • penalty JSON is decoded into PenaltyKey -> value map.
  • aux JSON is lazily decoded and only written when aux values change.
  • Rank data is tracked with:
    • rankVarRead (current read view)
    • rankVarIncrease (increment queue)
    • rankVarSet (explicit set queue)

Action Objects (iAction)

General composes action sources into a single list:

  1. Nation type (buildNationTypeClass)
  2. Officer level (TriggerOfficerLevel)
  3. Domestic special (buildGeneralSpecialDomesticClass)
  4. War special (buildGeneralSpecialWarClass)
  5. Personality (buildPersonalityClass)
  6. Crew type (GameUnitConst::byID)
  7. Inheritance buff (TriggerInheritBuff)
  8. Scenario effect (buildScenarioEffectClass)
  9. Items: horse / weapon / book / item (buildItemClass)

getActionList() returns this merged list and is the core entry point for modifiers and triggers.

Stat Computation

getStatValue() applies layered modifiers:

  • Base stat from raw value
  • Injury multiplier
  • Cross-stat adjust (strength/intel + 1/4 of the other stat)
  • Clamp to GameConst::$maxLevel
  • onCalcStat() from every action object
  • Cached by (statName, injury, action, adjust) tuple

Convenience wrappers:

  • getLeadership(), getStrength(), getIntel()

Turn Reservation and LastTurn

  • getReservedTurn(turnIdx) reads from general_turn.
  • When no entry exists, buildGeneralCommandClass(null) creates 휴식.
  • LastTurn holds { command, arg, term, seq } and is used by BaseCommand::addTermStack() to advance multi-turn commands.
  • applyDB() persists updated fields and writes last_turn if it changed.

Aux and Penalty Behavior

  • aux is loaded on demand (unpackAux()), and setAuxVar() writes through to general.aux only when values changed.
  • Setting an aux value to null deletes the key from JSON.
  • Command constraints that require aux values trigger General::unpackAux() before evaluation.
  • penalty is used in both General logic (AI and permission checks) and API flows (messages, nation tools); runtime expiration is not automatic.

Trigger and Modifier Hooks

General delegates calculations and trigger lists through action objects:

  • Economy/strategy: onCalcDomestic, onCalcStrategic, onCalcNationalIncome
  • Combat modifiers: onCalcStat, onCalcOpposeStat, getWarPowerMultiplier
  • Arbitrary actions: onArbitraryAction (used in city conquest)

Turn-prep triggers:

  • getPreTurnExecuteTriggerList() merges trigger lists from every action object. TurnExecutionHelper::preprocessCommand() adds che_부상경감 + che_병력군량소모 on top.

Battle triggers:

  • getBattleInitSkillTriggerList() merges per-action battle-init triggers.
  • getBattlePhaseSkillTriggerList() includes base phase triggers:
    • che_필살시도, che_필살발동
    • che_회피시도, che_회피발동
    • che_계략시도, che_계략발동, che_계략실패
    • plus any action-specific additions.

Rank and Access Log Updates

  • increaseRankVar() / setRankVar() queue updates until applyDB().
  • applyDB() updates general and rank_data, then flushes logs.
  • checkStatChange() uses *_exp thresholds to increase/decrease stats and logs level changes.

Open Questions / Follow-ups

  • PenaltyKey effects and how penalties are applied are outside this file.
  • GeneralBase and LazyVarAndAuxUpdater may contain additional state conventions for new code to mirror.