Skip to content

TargetType.AnyEnemy JSON actions silently target the first enemy when target_index is omitted #79

@CyberBarbarian

Description

@CyberBarbarian

The headless JSON protocol currently makes a gameplay choice for the caller when a TargetType.AnyEnemy action omits target_index.

Observed in current upstream main (04319e8):

  • RunSimulator.DoPlayCard() comments say AnyEnemy cards: use target_index or auto-pick first alive enemy, and the fallback uses the first alive enemy.
  • RunSimulator.DoUsePotion() does the same for TargetType.AnyEnemy potions.

This report is intentionally limited to TargetType.AnyEnemy, where the original game requires the player to choose one enemy. It is not about AOE cards or potions. Cards such as WHIRLWIND export target_type: AllEnemies and should be playable without target_index; the engine handles those as all-enemy effects.

Why this matters: when there are multiple enemies, selecting one enemy is a real game decision. Auto-targeting enemy 0 makes JSON clients believe they issued an under-specified action, but the backend has already changed game state.

Minimal repro shape:

{cmd:start_run,character:Ironclad,seed:explicit-target-repro,ascension:0,lang:en}
{cmd:set_player,deck:[STRIKE_IRONCLAD,STRIKE_IRONCLAD,STRIKE_IRONCLAD,STRIKE_IRONCLAD,STRIKE_IRONCLAD],potions:[FIRE_POTION]}
{cmd:enter_room,type:combat,encounter:SHRINKER_BEETLE_WEAK}
{cmd:action,action:play_card,args:{card_index:0}}

Current behavior: if card 0 is an enemy-targeted Strike, the backend targets the first alive enemy. The same pattern applies to:

{cmd:action,action:use_potion,args:{potion_index:0}}

Expected behavior: return an error or explicit pending-target state requiring target_index, without changing combat state. Self, all-enemy, all, and no-target cards/potions should still omit target_index.

I tested a local protocol-only patch that requires target_index for AnyEnemy cards and potions. It does not change card, potion, enemy, or combat effect logic; it only stops the headless adapter from making a silent single-target choice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions