Combat

Source: src/dungeon_combat.c · 79 lines · 7 functions.

Module responsibility

Creates encounters and resolves attacks, escape attempts, enemy turns and health-potion use.

See how this module fits into the complete Dungeon system →

Module entry points

These functions are exposed to the rest of the Dungeon system. Open one to follow its decisions and helper calls.

How to read these diagrams

Each function has an expandable structural diagram derived from the current C source. Decisions split into True and False, loop bodies are indented, and arrows show statement order.

These are source diagrams before preprocessing, not runtime traces. Callback execution, task scheduling and macro expansion are not inferred.

Functions in this file

combatDamage() · source line 6
static uint32_t combatDamage(uint16_t attack, uint16_t defence)

Calls into this documentation:

  1. Executeconst DungeonConfig *config = getDungeonConfig();
  2. Executeconst uint32_t roll = 1U + esp_random() % config->combatDiceSides;
  3. Executeconst uint32_t total = (uint32_t)attack + roll;
  4. Exit this functionreturn total > defence && total - defence > config->combatMinimumDamage ? total - defence : config->combatMinimumDamage;
Read original function source
static uint32_t combatDamage(uint16_t attack, uint16_t defence)
{
    const DungeonConfig *config = getDungeonConfig();
    const uint32_t roll = 1U + esp_random() % config->combatDiceSides;
    const uint32_t total = (uint32_t)attack + roll;
    return total > defence && total - defence > config->combatMinimumDamage ? total - defence : config->combatMinimumDamage;
}
applyDamage() · source line 14
static void applyDamage(uint16_t *health, uint32_t damage)
  1. Execute*health = damage >= *health ? 0U : (uint16_t)(*health - damage);
Read original function source
static void applyDamage(uint16_t *health, uint32_t damage)
{
    *health = damage >= *health ? 0U : (uint16_t)(*health - damage);
}
enemyAttack() · source line 19
static DungeonCombatResult enemyAttack(DungeonCombatState *state, DungeonPlayerState *player)

Calls into this documentation:

  1. Executestate->lastEnemyDamage = combatDamage(state->attack, player->defence);
  2. ExecuteapplyDamage(&player->health, state->lastEnemyDamage);
  3. Exit this functionreturn player->health == 0U ? DUNGEON_COMBAT_PLAYER_DEFEATED : DUNGEON_COMBAT_CONTINUES;
Read original function source
static DungeonCombatResult enemyAttack(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastEnemyDamage = combatDamage(state->attack, player->defence);
    applyDamage(&player->health, state->lastEnemyDamage);
    return player->health == 0U ? DUNGEON_COMBAT_PLAYER_DEFEATED : DUNGEON_COMBAT_CONTINUES;
}
startDungeonCombat() · source line 26
bool startDungeonCombat(uint8_t enemy_type, DungeonCombatState *state)

Calls into this documentation:

  1. Decisionstate == NULL
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  2. Executeconst DungeonConfig *config = getDungeonConfig();
  3. Executememset(state, 0, sizeof(*state));
  4. Executestate->enemyType = enemy_type;
  5. Select a caseenemy_type

    Enter matching case; follow source fall-through until a break, return or end.

      1. Case / labelcase DUNGEON_ENEMY_LEVEL_1:
      2. Executestate->health = config->enemyLevel1Health;
      3. Executestate->attack = config->enemyLevel1Attack;
      4. Executestate->defence = config->enemyLevel1Defence;
      5. Executestate->xpReward = config->enemyLevel1Xp;
      6. Exit enclosing loop or switchbreak;
      7. Case / labelcase DUNGEON_ENEMY_LEVEL_2:
      8. Executestate->health = config->enemyLevel2Health;
      9. Executestate->attack = config->enemyLevel2Attack;
      10. Executestate->defence = config->enemyLevel2Defence;
      11. Executestate->xpReward = config->enemyLevel2Xp;
      12. Exit enclosing loop or switchbreak;
      13. Case / labelcase DUNGEON_ENEMY_LEVEL_3:
      14. Executestate->health = config->enemyLevel3Health;
      15. Executestate->attack = config->enemyLevel3Attack;
      16. Executestate->defence = config->enemyLevel3Defence;
      17. Executestate->xpReward = config->enemyLevel3Xp;
      18. Exit enclosing loop or switchbreak;
      19. Case / labelcase DUNGEON_ENEMY_LEVEL_4:
      20. Executestate->health = config->enemyLevel4Health;
      21. Executestate->attack = config->enemyLevel4Attack;
      22. Executestate->defence = config->enemyLevel4Defence;
      23. Executestate->xpReward = config->enemyLevel4Xp;
      24. Exit enclosing loop or switchbreak;
      25. Case / labelcase DUNGEON_ENEMY_DRAGON:
      26. Executestate->health = config->dragonHealth;
      27. Executestate->attack = config->dragonAttack;
      28. Executestate->defence = config->dragonDefence;
      29. Executestate->xpReward = config->dragonXp;
      30. Exit enclosing loop or switchbreak;
      31. Case / labeldefault:
      32. Exit this functionreturn false;
  6. Executestate->maxHealth = state->health;
  7. Exit this functionreturn true;
Read original function source
bool startDungeonCombat(uint8_t enemy_type, DungeonCombatState *state)
{
    if (state == NULL) return false;
    const DungeonConfig *config = getDungeonConfig();
    memset(state, 0, sizeof(*state));
    state->enemyType = enemy_type;
    switch (enemy_type) {
        case DUNGEON_ENEMY_LEVEL_1:
            state->health = config->enemyLevel1Health; state->attack = config->enemyLevel1Attack;
            state->defence = config->enemyLevel1Defence; state->xpReward = config->enemyLevel1Xp; break;
        case DUNGEON_ENEMY_LEVEL_2:
            state->health = config->enemyLevel2Health; state->attack = config->enemyLevel2Attack;
            state->defence = config->enemyLevel2Defence; state->xpReward = config->enemyLevel2Xp; break;
        case DUNGEON_ENEMY_LEVEL_3:
            state->health = config->enemyLevel3Health; state->attack = config->enemyLevel3Attack;
            state->defence = config->enemyLevel3Defence; state->xpReward = config->enemyLevel3Xp; break;
        case DUNGEON_ENEMY_LEVEL_4:
            state->health = config->enemyLevel4Health; state->attack = config->enemyLevel4Attack;
            state->defence = config->enemyLevel4Defence; state->xpReward = config->enemyLevel4Xp; break;
        case DUNGEON_ENEMY_DRAGON:
            state->health = config->dragonHealth; state->attack = config->dragonAttack;
            state->defence = config->dragonDefence; state->xpReward = config->dragonXp; break;
        default: return false;
    }
    state->maxHealth = state->health;
    return true;
}
dungeonCombatAttack() · source line 54
DungeonCombatResult dungeonCombatAttack(DungeonCombatState *state, DungeonPlayerState *player)

Calls into this documentation:

  1. Executestate->lastPlayerDamage = 0U;
  2. Executestate->lastEnemyDamage = 0U;
  3. Executestate->lastPlayerDamage = combatDamage(player->attack, state->defence);
  4. ExecuteapplyDamage(&state->health, state->lastPlayerDamage);
  5. Exit this functionreturn state->health == 0U ? DUNGEON_COMBAT_ENEMY_DEFEATED : enemyAttack(state, player);
Read original function source
DungeonCombatResult dungeonCombatAttack(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastPlayerDamage = 0U;
    state->lastEnemyDamage = 0U;
    state->lastPlayerDamage = combatDamage(player->attack, state->defence);
    applyDamage(&state->health, state->lastPlayerDamage);
    return state->health == 0U ? DUNGEON_COMBAT_ENEMY_DEFEATED : enemyAttack(state, player);
}
dungeonCombatAttemptRun() · source line 63
DungeonCombatResult dungeonCombatAttemptRun(DungeonCombatState *state, DungeonPlayerState *player)

Calls into this documentation:

  1. Executestate->lastPlayerDamage = 0U;
  2. Executestate->lastEnemyDamage = 0U;
  3. Decisionesp_random() % 100U < getDungeonConfig()->runChancePercent
    True
    1. Exit this functionreturn DUNGEON_COMBAT_ESCAPED;
    False

    Continue after this decision.

  4. Exit this functionreturn enemyAttack(state, player) == DUNGEON_COMBAT_PLAYER_DEFEATED ? DUNGEON_COMBAT_PLAYER_DEFEATED : DUNGEON_COMBAT_RUN_FAILED;
Read original function source
DungeonCombatResult dungeonCombatAttemptRun(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastPlayerDamage = 0U;
    state->lastEnemyDamage = 0U;
    if (esp_random() % 100U < getDungeonConfig()->runChancePercent) return DUNGEON_COMBAT_ESCAPED;
    return enemyAttack(state, player) == DUNGEON_COMBAT_PLAYER_DEFEATED ? DUNGEON_COMBAT_PLAYER_DEFEATED : DUNGEON_COMBAT_RUN_FAILED;
}
dungeonCombatUsePotion() · source line 71
DungeonCombatResult dungeonCombatUsePotion(DungeonCombatState *state, DungeonPlayerState *player)

Calls into this documentation:

  1. Executestate->lastPlayerDamage = 0U;
  2. Executestate->lastEnemyDamage = 0U;
  3. Decisionplayer->healthPotions == 0U
    True
    1. Exit this functionreturn DUNGEON_COMBAT_POTION_UNAVAILABLE;
    False

    Continue after this decision.

  4. Execute--player->healthPotions;
  5. Executeplayer->health = player->maxHealth;
  6. Exit this functionreturn enemyAttack(state, player);
Read original function source
DungeonCombatResult dungeonCombatUsePotion(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastPlayerDamage = 0U;
    state->lastEnemyDamage = 0U;
    if (player->healthPotions == 0U) return DUNGEON_COMBAT_POTION_UNAVAILABLE;
    --player->healthPotions;
    player->health = player->maxHealth;
    return enemyAttack(state, player);
}
Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "dungeon_combat.h"
#include "dungeon_config.h"
#include "esp_random.h"
#include <string.h>

static uint32_t combatDamage(uint16_t attack, uint16_t defence)
{
    const DungeonConfig *config = getDungeonConfig();
    const uint32_t roll = 1U + esp_random() % config->combatDiceSides;
    const uint32_t total = (uint32_t)attack + roll;
    return total > defence && total - defence > config->combatMinimumDamage ? total - defence : config->combatMinimumDamage;
}

static void applyDamage(uint16_t *health, uint32_t damage)
{
    *health = damage >= *health ? 0U : (uint16_t)(*health - damage);
}

static DungeonCombatResult enemyAttack(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastEnemyDamage = combatDamage(state->attack, player->defence);
    applyDamage(&player->health, state->lastEnemyDamage);
    return player->health == 0U ? DUNGEON_COMBAT_PLAYER_DEFEATED : DUNGEON_COMBAT_CONTINUES;
}

bool startDungeonCombat(uint8_t enemy_type, DungeonCombatState *state)
{
    if (state == NULL) return false;
    const DungeonConfig *config = getDungeonConfig();
    memset(state, 0, sizeof(*state));
    state->enemyType = enemy_type;
    switch (enemy_type) {
        case DUNGEON_ENEMY_LEVEL_1:
            state->health = config->enemyLevel1Health; state->attack = config->enemyLevel1Attack;
            state->defence = config->enemyLevel1Defence; state->xpReward = config->enemyLevel1Xp; break;
        case DUNGEON_ENEMY_LEVEL_2:
            state->health = config->enemyLevel2Health; state->attack = config->enemyLevel2Attack;
            state->defence = config->enemyLevel2Defence; state->xpReward = config->enemyLevel2Xp; break;
        case DUNGEON_ENEMY_LEVEL_3:
            state->health = config->enemyLevel3Health; state->attack = config->enemyLevel3Attack;
            state->defence = config->enemyLevel3Defence; state->xpReward = config->enemyLevel3Xp; break;
        case DUNGEON_ENEMY_LEVEL_4:
            state->health = config->enemyLevel4Health; state->attack = config->enemyLevel4Attack;
            state->defence = config->enemyLevel4Defence; state->xpReward = config->enemyLevel4Xp; break;
        case DUNGEON_ENEMY_DRAGON:
            state->health = config->dragonHealth; state->attack = config->dragonAttack;
            state->defence = config->dragonDefence; state->xpReward = config->dragonXp; break;
        default: return false;
    }
    state->maxHealth = state->health;
    return true;
}

DungeonCombatResult dungeonCombatAttack(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastPlayerDamage = 0U;
    state->lastEnemyDamage = 0U;
    state->lastPlayerDamage = combatDamage(player->attack, state->defence);
    applyDamage(&state->health, state->lastPlayerDamage);
    return state->health == 0U ? DUNGEON_COMBAT_ENEMY_DEFEATED : enemyAttack(state, player);
}

DungeonCombatResult dungeonCombatAttemptRun(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastPlayerDamage = 0U;
    state->lastEnemyDamage = 0U;
    if (esp_random() % 100U < getDungeonConfig()->runChancePercent) return DUNGEON_COMBAT_ESCAPED;
    return enemyAttack(state, player) == DUNGEON_COMBAT_PLAYER_DEFEATED ? DUNGEON_COMBAT_PLAYER_DEFEATED : DUNGEON_COMBAT_RUN_FAILED;
}

DungeonCombatResult dungeonCombatUsePotion(DungeonCombatState *state, DungeonPlayerState *player)
{
    state->lastPlayerDamage = 0U;
    state->lastEnemyDamage = 0U;
    if (player->healthPotions == 0U) return DUNGEON_COMBAT_POTION_UNAVAILABLE;
    --player->healthPotions;
    player->health = player->maxHealth;
    return enemyAttack(state, player);
}