C言語入門|STEP17:アイテムと装備処理の実装-所持管理・使用・装備判定の考え方

はじめに:アイテムがあるから冒険は続く

STEP16では、ターン制バトルの内部構造を解説しました。
STEP17では、RPGに欠かせない アイテムと装備の仕組み を詳しく見ていきます。

アイテムは、

  • ピンチを立て直す
  • 戦略の幅を広げる
  • 探索のご褒美になる

といった重要な役割を持っています。
このRPGでは、シンプルだけど拡張しやすい設計 でアイテムを実装しています。

アイテムをIDで管理する設計

まず、アイテムは列挙型で定義されています。

typedef enum {
    ITEM_POTION = 0,
    ITEM_HIPOTION,
    ITEM_ETHER,
    ITEM_ELIXIR,
    ITEM_BRONZE_SWORD,
    ITEM_STEEL_SWORD,
    ITEM_APPRENTICE_STAFF,
    ITEM_SAGE_STAFF,
    ITEM_COUNT
} ItemID;

この設計のポイント

  • アイテムを数値IDで一意に管理
  • ITEM_COUNT で総数を把握
  • 配列と組み合わせやすい

RPGでは、
アイテムID=配列の添字
という考え方がとても便利です。

所持アイテムの管理方法

所持数は、GameState の配列で管理されています。

int inv[ITEM_COUNT];

なぜ配列なのか

理由内容
高速添字アクセスですぐ取得
単純個数管理が簡単
保存しやすいセーブが楽

マップ探索や戦闘で増減するため、
数値管理が最も安定する設計 です。

アイテムの種類を分類する理由

アイテムには、種類があります。

typedef enum { IT_CONSUME = 0, IT_WEAPON = 1, IT_STAFF = 2 } ItemType;

分類の意味

種類内容
IT_CONSUME消費アイテム
IT_WEAPON武器
IT_STAFF

この分類によって、

  • 使用処理
  • 装備処理

同じ入口で分岐 できるようになります。

アイテム定義テーブルの役割

実際のアイテム情報は、
ItemDef 配列でまとめられています。

static const ItemDef g_items[ITEM_COUNT] = {
    {"ポーション", IT_CONSUME, 30},
    {"ハイポーション", IT_CONSUME, 70},
    {"エーテル", IT_CONSUME, 15},
    {"エリクサー", IT_CONSUME, 999},
    {"ブロンズソード", IT_WEAPON, 3},
    {"スチールソード", IT_WEAPON, 6},
    {"見習いの杖", IT_STAFF, 3},
    {"賢者の杖", IT_STAFF, 6},
};

このテーブルが表すもの

要素意味
name表示名
typeアイテム種別
value回復量や補正値

ロジックとデータを分けることで、
数値調整だけを安全に行える設計 になっています。

アイテムを使えるかどうかの判定

戦闘中、まず確認されるのが
アイテムが1つでもあるかどうかです。

static int any_item_available(const int inv[]) {
    for (int i = 0; i < ITEM_COUNT; i++)
        if (inv[i] > 0) return 1;
    return 0;
}

このチェックの意味

  • 無駄な選択肢を表示しない。
  • 入力ミスを防ぐ。

プレイヤー体験を意識した、
親切なガード処理 です。

消費アイテムの使用処理

消費アイテムは、
use_consumable_on 関数で処理されます。

static void use_consumable_on(Character* c, ItemID id) {
    if (id == ITEM_POTION || id == ITEM_HIPOTION) {
        c->hp += g_items[id].value;
        if (c->hp > c->max_hp) c->hp = c->max_hp;
    }
}

ポイント解説

  • 回復量はテーブル参照
  • 最大値を超えないよう制御
  • キャラを直接更新

この関数を使うことで、
どの場面でも同じ回復処理 が使えます。

装備処理と職業制限

装備アイテムは、
equip_item 関数で処理されます。

if (g_items[id].type == IT_WEAPON) {
    if (c->job == HERO || c->job == WARRIOR) {
        c->weapon_atk = g_items[id].value;
    }
}

なぜ職業制限を入れるのか

  • 職業ごとの役割を明確にする。
  • 全員が万能にならない。
  • RPGらしい選択を生む。

装備可能かどうかを
関数内で判断している点 が重要です。

装備は上書き方式にしている理由

装備を変更すると、

  • 以前の装備は自動的に外れる。
  • 補正値だけが更新される。

という設計になっています。

この方式のメリット

  • 管理がシンプル
  • 装備スロットを持たなくて済む。
  • 学習用として分かりやすい。

複雑な装備管理は、
次のステップで拡張可能です。

戦闘中のアイテム使用フロー

戦闘中の流れは次のとおりです。

  1. 所持アイテム一覧を表示
  2. 使用・装備するアイテムを選択
  3. 消費か装備かを判定
  4. 対象キャラに反映

この一連の流れが、
1ターンの行動として完結 しています。

STEP17で押さえておきたいポイントまとめ

STEP17で理解しておきたいポイントはこちらです。

  • アイテムはIDと配列で管理する。
  • アイテム情報はテーブルで定義する。
  • 消費と装備は種別で分岐する。
  • 装備制限で職業の個性を保つ。
  • 処理は関数にまとめて再利用する。