Enemy Data & AI

Status: Designed Author: user + game-designer Last Updated: 2026-03-28 System Index: #8 — MVP, Core Layer

Overview

The Enemy Data & AI system defines enemy data resources (stats, intents, scaling) and the AI logic that selects enemy actions each turn. Enemies are data-driven Godot Resources (.tres), similar to cards. Basic enemies use fixed action patterns (repeating sequences) for learnability. Elites and bosses use conditional logic (state-based decisions) for depth. All enemies telegraph their next action via intent icons before the player phase, giving players information to react to.

Player Fantasy

"I can read the battlefield and make smart decisions." Intent telegraphing turns combat into a puzzle — players see what's coming and choose how to respond. Basic enemies are learnable patterns you master; elites and bosses force you to adapt. In co-op, visible intents create natural coordination: "The boss is hitting for 20 — someone needs to block."

Detailed Design

Core Rules

  1. Every enemy type is an EnemyData Godot Resource (.tres) stored in assets/data/enemies/.
  2. Enemies are spawned by the Combat System based on the current map node (encounter table).
  3. Each enemy has a list of actions it can perform. Actions are selected by the AI each turn.
  4. Before the player phase, all enemies reveal their intent — the action they will perform in the upcoming enemy phase.
  5. During the enemy phase, enemies execute their revealed intent in order (left to right on screen).
  6. Enemy HP scales with player count. Other stats do not scale.
  7. All enemy state and AI runs server-side only.

EnemyData Resource Schema

FieldTypeDescription
idStringNameUnique identifier (e.g., "slime", "goblin_shaman")
display_nameStringPlayer-facing name
base_hpintHP for a 2-player game (scales with player count)
actionsArray[EnemyAction]Available actions this enemy can perform
ai_typeAIType enumPATTERN or CONDITIONAL
action_patternArray[int]For PATTERN AI: indices into actions array, repeating
conditionsArray[AICondition]For CONDITIONAL AI: ordered conditions with action indices
tierEnemyTier enumBASIC, ELITE, BOSS
art_idStringNameReference to enemy art asset

EnemyAction Resource Schema

FieldTypeDescription
action_typeEnemyActionType enumATTACK, DEFEND, BUFF, DEBUFF, HEAL, SUMMON
valueintDamage/block/heal amount
status_idStringNameStatus effect to apply (if BUFF/DEBUFF)
status_stacksintStacks of status to apply
intent_iconStringNameIcon shown during telegraphing
targetEnemyTarget enumALL_PLAYERS, RANDOM_PLAYER, SELF, ALL_ENEMIES

AICondition Resource Schema (CONDITIONAL AI only)

FieldTypeDescription
condition_typeConditionType enumHP_BELOW_PERCENT, TURN_NUMBER, STATUS_ACTIVE, ALWAYS
thresholdfloatComparison value (e.g., 0.5 for 50% HP)
paramStringNameOptional param (e.g., status name)
action_indexintIndex into actions array if condition is true

Conditions are evaluated top to bottom. First match wins. Last condition should always be ALWAYS as a fallback.

Enums

  • AIType: PATTERN, CONDITIONAL
  • EnemyTier: BASIC, ELITE, BOSS
  • EnemyActionType: ATTACK, DEFEND, BUFF, DEBUFF, HEAL, SUMMON
  • EnemyTarget: ALL_PLAYERS, RANDOM_PLAYER, SELF, ALL_ENEMIES
  • ConditionType: HP_BELOW_PERCENT, TURN_NUMBER, STATUS_ACTIVE, ALWAYS

AI Selection Logic

PATTERN AI (basic enemies):

current_action_index = action_pattern[turn_number % action_pattern.size()]
next_intent = actions[current_action_index]

Example: Slime with pattern [0, 0, 1] and actions [Attack 8, Defend 6] → Attack, Attack, Defend, Attack, Attack, Defend…

CONDITIONAL AI (elites/bosses):

for condition in conditions:
    if evaluate(condition, enemy_state):
        next_intent = actions[condition.action_index]
        break

Example: Goblin Shaman with conditions:

  1. HP_BELOW_PERCENT 0.3 → action[2] (Heal 15)
  2. TURN_NUMBER == 0 → action[1] (Buff: +3 Strength to all enemies)
  3. ALWAYS → action[0] (Attack 10)

HP Scaling

Player CountHP Multiplier
1x0.75
2x1.0 (base)
3x1.5
4x2.0
actual_hp = floor(base_hp * hp_multiplier[player_count])

Intent Telegraphing

Each action type has a standard intent icon:

Action TypeIconColor
ATTACKSwordRed
DEFENDShieldBlue
BUFFUp arrowGreen
DEBUFFDown arrowPurple
HEALHeartGreen
SUMMONPlus signYellow

The intent shows the icon + value (e.g., sword icon with "12" = attacking for 12). Players can see exactly what's coming.

V1 Enemy Roster

EnemyTierHP (2p)AIPattern/Conditions
SlimeBASIC30PATTERNAttack 8, Attack 8, Defend 5
GoblinBASIC24PATTERNAttack 6, Attack 10
SkeletonBASIC35PATTERNAttack 6, Debuff (Weak 1), Attack 12
MushroomBASIC28PATTERNDebuff (Poison 3), Attack 5, Attack 5
Shield BeetleBASIC40PATTERNDefend 10, Attack 7, Attack 7
Goblin ShamanELITE55CONDITIONALTurn 0: Buff (+2 Str all enemies), HP<30%: Heal 15, else: Attack 12
Dark KnightELITE70CONDITIONALHP<50%: Buff (+3 Str self), else: Attack 15 with Debuff (Vulnerable 2)
DragonBOSS120CONDITIONALTurn 0: Buff (+2 Str self), HP<30%: Attack 25 (ALL_PLAYERS), HP<60%: Attack 18, else: Attack 12 + Debuff (Weak 1)

Encounter Tables

Node TypeEnemiesCount
COMBAT1-3 BASIC enemies (random from pool)Most common
ELITE1 ELITE + 0-1 BASIC enemiesLess common
BOSS1 BOSSFinal node only

States and Transitions

Per-enemy runtime state during combat:

FieldTypeDescription
current_hpintRemaining HP
statusesDictionaryActive status effects and stack counts
turn_numberintHow many turns this enemy has taken (for PATTERN index and CONDITIONAL checks)
current_intentEnemyActionThe telegraphed action for the current turn
is_aliveboolFalse when HP reaches 0

Enemy lifecycle: SPAWNED → ALIVE (selecting intents, taking actions) → DEAD (HP = 0, removed from combat)

Interactions with Other Systems

SystemDirectionInterface
Game State ManagerReadsPlayer count for HP scaling, encounter_count for future difficulty scaling
Combat SystemCalled byCombat spawns enemies, triggers intent selection at round start, triggers action execution in enemy phase
Card Effect ResolverCalled byResolver deals damage to enemies, applies statuses
Player ResourcesCallsEnemy attacks call deal_damage() on targeted players
Status Effect SystemBidirectionalEnemies can have statuses (Vulnerable, Weak, Strength). Status system ticks enemy statuses at phase boundaries.
Combat UIReadsUI displays enemy art, HP bar, intent icon, status icons

Formulas

Enemy Damage Output

base_damage = action.value
if enemy has Strength: base_damage += strength_stacks
if enemy has Weak: base_damage = floor(base_damage * 0.75)
# Then passed to Player Resources damage resolution (Vulnerable check, Block, etc.)

Encounter Difficulty (V1 — simple)

encounter_value = sum(enemy.base_hp for each enemy in encounter)

Target ranges:

  • COMBAT: 50-100 encounter value (2p base)
  • ELITE: 80-130 encounter value
  • BOSS: 120 encounter value (single enemy)

Expected Run Damage Budget

Across an 8-node run (5 combats, 1 elite, 1 rest, 1 boss):

  • Basic combats deal ~15-25 damage per player per encounter (after block)
  • Elite deals ~20-35 damage per player
  • Boss deals ~25-40 damage per player
  • Total expected damage: ~120-180 per player
  • Starting HP: 60, one rest heals ~18 → budget of ~78 HP
  • This means players MUST block effectively — can't just face-tank everything

Edge Cases

CaseResolution
Enemy has 0 HP from player cardsMark is_alive = false. Skip this enemy's intent execution in enemy phase. Remove from targeting.
All enemies die mid-player-phaseCombat ends immediately. Skip enemy phase. Proceed to reward.
Enemy targets RANDOM_PLAYER but some players are deadOnly target living players. If all players dead, GAME_OVER.
Enemy buffs ALL_ENEMIES but some enemies are deadOnly buff living enemies.
CONDITIONAL AI: no condition matchesShould never happen if last condition is ALWAYS. If it does, default to first action. Log warning.
PATTERN AI: pattern array is emptyInvalid data. Log error. Default to first action in actions array.
Enemy with Strength buff deals DEBUFF actionStrength only modifies ATTACK actions. Non-attack actions are unaffected.
Enemy action targets SELF for ATTACKValid edge case for future self-damage mechanics. Resolve normally.
1-player game HP scaling (x0.75)floor() the result. A 30 HP slime becomes 22 HP solo.

Dependencies

Upstream

SystemDependency TypeInterface
Game State ManagerSoftReads player count for HP scaling

Downstream

SystemDependency TypeInterface
Combat SystemHardSpawns enemies, triggers AI, executes intents
Card Effect ResolverHardTargets enemies with card damage/status effects
Combat UIHardDisplays enemy sprites, HP, intents, statuses
Co-op MechanicsSoftEnemy count used by PER_ENEMY modifier
Map SystemSoftMap node types reference encounter tier (COMBAT/ELITE/BOSS)

Contracts

  • Enemy data resources are read-only at runtime. Runtime state (current_hp, statuses, turn_number) is held separately.
  • Only the Combat System creates enemy instances. Other systems interact via the Combat System's enemy list.
  • Intent is selected and revealed before the player phase. Intent cannot change during the player phase.

Tuning Knobs

KnobDefaultSafe RangeAffects
Per-enemy base_hpVaries20-150Combat length per enemy
Per-enemy action valueVaries4-25Damage pressure, block value
HP scaling multipliers0.75/1.0/1.5/2.0Adjust per tierCo-op balance — too high = tedious, too low = trivial
Encounter composition (enemy count)1-3 basic, 1-2 elite1-4Action economy — more enemies = more incoming damage per round
CONDITIONAL thresholdsVaries0.1-0.9When elites/bosses change behavior
Status stacks on debuff actions1-31-5Debuff pressure on players

Interaction warning: Enemy damage output × enemies per encounter × rounds per combat must be balanced against player HP + Block generation. If players generate ~15 Block per turn and face 20 damage, they lose ~5 HP per round → ~6 rounds of combat budget before dying.

Acceptance Criteria

#CriterionVerification
1All V1 enemies (5 basic, 2 elite, 1 boss) load without errorsUnit test: load each .tres, assert all fields valid
2PATTERN AI cycles correctlyUnit test: Slime pattern [0,0,1] over 6 turns → 0,0,1,0,0,1
3CONDITIONAL AI evaluates top-to-bottom, first match winsUnit test: Goblin Shaman at 25% HP → selects Heal, not Attack
4HP scales correctly for 1-4 playersUnit test: 30 base HP → 22, 30, 45, 60 for 1-4 players
5Intent is visible before player phaseIntegration test: start combat, assert all enemies have a non-null current_intent
6Dead enemies are skipped in enemy phaseUnit test: kill enemy, trigger enemy phase, assert no action from dead enemy
7Enemy Strength modifies attack damageUnit test: enemy with 2 Strength, 8 base attack → 10 damage
8Encounter tables produce valid compositionsUnit test: generate COMBAT encounter, assert 1-3 BASIC enemies
Built with LogoFlowershow