C言語入門|STEP14:魔法とスキルの実装ロジック-Spell構造体と効果分岐処理

はじめに:魔法がRPGの戦略性を生む

STEP13では、経験値とレベルアップによる成長システムを解説しました。
STEP14では、戦闘の幅を一気に広げる 魔法とスキルの実装 を読み解いていきます。

魔法があることで、

  • 攻撃一辺倒にならない。
  • 回復や強化という選択肢が生まれる。
  • 職業ごとの個性がはっきりする。

といった、RPGらしい戦略性が生まれます。

魔法を表す Spell 構造体

まずは、魔法の基本定義から見てみましょう。

typedef enum { SPELL_DMG = 0, SPELL_HEAL = 1, SPELL_BUFF = 2 } SpellType;

typedef struct {
    char name[24];
    SpellType type;
    int mp_cost;
    int power;
} Spell;

この構造体が表しているもの

メンバ役割
name魔法名
type効果の種類
mp_cost消費MP
power威力または効果量

魔法を「名前・種類・消費・効果量」に分解しているため、
処理の共通化がしやすい設計 になっています。

魔法の種類を enum で管理する理由

SpellType は、魔法の効果を分類するための列挙型です。

種類意味
SPELL_DMGダメージ魔法
SPELL_HEAL回復魔法
SPELL_BUFF強化・防御魔法

この分類のおかげで、

  • 魔法の処理を switch や if で分岐できる。
  • 新しい魔法を追加しやすい。

というメリットがあります。

職業ごとの魔法を初期化する仕組み

魔法は init_spells 関数で、
職業ごとに4つずつ設定 されています。

static void init_spells(Character* c) {
    if (c->job == HERO) {
        c->spells[0] = (Spell){ "ヒール", SPELL_HEAL, 4, 25 };
        c->spells[1] = (Spell){ "ホーリーブレード", SPELL_DMG, 5, 2 };
        c->spells[2] = (Spell){ "ガードオーラ", SPELL_BUFF, 4, 1 };
        c->spells[3] = (Spell){ "スマイト", SPELL_DMG, 7, 3 };
    }
    // 他職業も同様
}

なぜ初期化関数にまとめているのか

  • 職業ごとの魔法セットが一目で分かる。
  • キャラクター初期化と連動しやすい。
  • 魔法バランスの調整が楽。

RPGでは、
「どの職業がどんな魔法を使えるか」
が設計の要になります。

魔法選択と使用処理の流れ

戦闘中に魔法を選ぶと、
cast_spell 関数が呼ばれます。

static int cast_spell(Character* caster, Character party[],
                      Enemy* enemy, int spell_index)

この関数は、

  • 魔法の妥当性チェック
  • MP消費
  • 効果の適用

を一手に引き受けています。

MP不足チェックの重要性

魔法使用の最初に、
MPが足りているかを確認しています。

if (caster->mp < sp.mp_cost) {
    printf("MPが足りない!\n");
    return 0;
}

なぜここでチェックするのか

  • MPがマイナスになるのを防ぐ
  • 使用失敗を明確に伝える

こうしたチェックを入れておくことで、
ゲームの挙動が安定 します。

ダメージ魔法の計算ロジック

ダメージ魔法では、
魔力と power を組み合わせてダメージを計算しています。

int dmg = char_mag(caster) * sp.power;

この設計のポイント

  • 魔力が高いほど強くなる。
  • 魔法ごとの威力差を power で表現

レベルアップや装備が、
魔法の強さに直接反映される 仕組みです。

回復魔法の対象選択処理

回復魔法では、
回復対象をプレイヤーに選ばせます。

printf("回復対象を選んでください (1-%d): ", PARTY_SIZE);

なぜ自動回復にしないのか

  • 誰を優先するかが戦略になる。
  • パーティ編成の意味が出る。

回復対象を選ばせるだけで、
戦闘の考えどころが一気に増えます。

強化・防御魔法の扱い方

強化系魔法は、
ステータスを直接変更するか、防御フラグを立てます。

caster->defending = 1;

フラグで管理するメリット

  • 次の攻撃だけ効果を発揮
  • 処理がシンプル
  • 状態異常の拡張にも使える。

数値を複雑にいじらず、
状態フラグで表現しているのがポイント です。

魔法処理を1つの関数にまとめる理由

cast_spell に処理を集約していることで、

  • バトル処理が読みやすい。
  • 魔法追加時の修正箇所が少ない。
  • バグが入りにくい。

という利点があります。

RPGでは、
魔法処理は必ず一元管理する
という意識が大切です。

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

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

  • 魔法は Spell 構造体で定義する。
  • 効果の種類は enum で分類する。
  • 職業ごとに魔法セットを持たせる。
  • MPチェックは必須
  • 魔法処理は1関数にまとめる。