
STEP13:ラストボス戦の実装(マスタードラゴン・専用魔法・エンディング導入)
STEP13では、いよいよラストボス「マスタードラゴン」を実装します。
通常の敵とは“格”が違う演出にしたいので、今回は次をまとめて入れます。
- マスタードラゴン専用テンプレート(固定出現)
- 専用魔法(強力攻撃/全体攻撃/自己強化など)
- 撃破したらエンディングへ導入(ui層のエンディング表示)
実装の全体像(どの層を触る?)
| 層 | 追加/変更内容 |
|---|---|
| enemies層 | マスタードラゴンのテンプレート追加、専用魔法定義、生成関数追加 |
| battle層 | 「ボス戦」用の戦闘開始、専用行動(演出・全体攻撃など)対応 |
| map層 | ボス部屋/ボス出現トリガ(例:特定座標・最深部) |
| ui層 | 撃破後にエンディング導入(ending画面へ) |
このSTEPでは「ボス戦はイベント」なので、ランダムエンカウントとは別ルートで呼び出すのが扱いやすいです。
enemies層:マスタードラゴンのテンプレートを追加
敵IDに「ボス」を追加
enemies.h(例)
typedef enum {
ENEMY_SLIME = 0,
ENEMY_GOBLIN,
ENEMY_WOLF,
ENEMY_MAGE,
ENEMY_GOLEM,
ENEMY_MASTER_DRAGON /* 追加 */
} EnemyId;
Enemy enemies_create(EnemyId id);
Enemy enemies_create_boss_master_dragon(void); /* 追加 */マスタードラゴンのパラメータ設計(例)
| 項目 | 値(例) | 意図 |
|---|---|---|
| max_hp | 900 | 長期戦 |
| atk | 55 | 通常攻撃でも痛い |
| def | 30 | 物理が通りにくい |
| mag | 60 | 魔法が脅威 |
| mdef | 25 | 魔法でも削れるが簡単ではない |
| max_mp | 180 | 専用魔法連打できる |
| ai_heal_threshold | 40% | 回復優先がやや早い |
※数値はあなたの既存バランスに合わせて調整してOKです。
専用魔法を定義する
ここでは「敵専用魔法」を以下3種類にします。
| 魔法名 | 種類 | 対象 | 効果 |
|---|---|---|---|
| Dragon Breath | ダメージ | 全体 | 炎の全体攻撃 |
| Ancient Roar | 強化 | 自分 | 攻撃力アップ(数ターン) |
| Dark Regeneration | 回復 | 自分 | 大回復 |
全体攻撃を入れることで「ラスボス感」が一気に出ます。
enemies.c(例:生成)
#include "enemies.h"
#include <string.h>
static void set_spell(Spell* s, const char* name, int type, int mp, int power) {
strncpy(s->name, name, sizeof(s->name)-1);
s->name[sizeof(s->name)-1] = '\0';
s->type = type; /* SPELL_DMG / SPELL_HEAL / SPELL_BUFF */
s->mp_cost = mp;
s->power = power;
}
Enemy enemies_create_boss_master_dragon(void) {
Enemy e;
memset(&e, 0, sizeof(e));
strcpy(e.name, "Master Dragon");
e.max_hp = 900; e.hp = e.max_hp;
e.atk = 55;
e.def = 30;
e.mag = 60;
e.mdef = 25;
e.max_mp = 180; e.mp = e.max_mp;
e.defending = 0;
/* 専用魔法 */
set_spell(&e.spells[0], "Dragon Breath", SPELL_DMG, 25, 22); /* 全体攻撃に使う */
set_spell(&e.spells[1], "Ancient Roar", SPELL_BUFF, 18, 20);/* 自己強化 */
set_spell(&e.spells[2], "Dark Regen", SPELL_HEAL, 20, 180);/* 大回復 */
/* 残りは空 */
e.kind = ENEMY_MASTER_DRAGON;
return e;
}battle層:ボス専用の戦闘処理を追加
「ボス戦開始」関数を用意
battle.h
int battle_boss_master_dragon(Character party[PARTY_SIZE]);戻り値は例えば
- 1:勝利
- 0:敗北(全滅)
にしておくと、呼び出し側(map/main)が分岐しやすいです。
全体攻撃対応(Dragon Breath)
既存の魔法が単体前提なら、battle側で“全体適用”にするのが簡単です。
Spellに target を追加できるならベストですが、まずは「魔法名」や「kind」で分岐してもOKです。
battle.c(例:ドラゴンブレス実装)
static void boss_cast_dragon_breath(Enemy* boss, Character party[PARTY_SIZE]) {
Spell sp = boss->spells[0]; /* Dragon Breath */
boss->mp -= sp.mp_cost;
printf("Master Dragon uses DRAGON BREATH!!\n");
sfx_beep(1);
for (int i = 0; i < PARTY_SIZE; i++) {
if (!party[i].alive) continue;
int base = boss->mag * sp.power - party[i].mdef;
if (base < 1) base = 1;
int dmg = apply_variance(base); /* 既存のブレ関数がある想定 */
apply_damage_to_char(&party[i], dmg);
printf("%s takes %d damage!\n", party[i].name, dmg);
}
}自己強化(Ancient Roar)を実装
強化は「一時的な補正」を battle側に持つと良いです。
例:Enemyに buff_atk_turns と buff_atk_rate を持たせる、もしくは battle側で管理します。
ここでは最小で boss->atk を一定ターンだけ上げる方式にします。
static void boss_cast_ancient_roar(Enemy* boss) {
Spell sp = boss->spells[1];
boss->mp -= sp.mp_cost;
boss->buff_atk_turns = 3; /* 3ターン攻撃上昇 */
boss->buff_atk_rate = 130; /* 130% */
printf("Master Dragon uses ANCIENT ROAR! ATK up!\n");
sfx_beep(0);
}敵の攻撃計算で
int atk = boss->atk;
if (boss->buff_atk_turns > 0) atk = atk * boss->buff_atk_rate / 100;のように適用します。
ターン終了時に buff_atk_turns-- を忘れずに。
大回復(Dark Regen)
STEP12で回復魔法は作っているはずなので、boss専用で「回復量が大きい」だけにします。
ボスAI:専用ロジックを用意する
通常敵AI(STEP12)のままでも動きますが、ラスボスは「パターン」があると面白いです。
今回のボスAI例:
- HP 50%以下:回復(Dark Regen)を狙う確率アップ
- 3ターン周期:Dragon Breath(全体)を混ぜる。
- 強化が切れている:Ancient Roar をたまに使う。
- それ以外:通常攻撃
battle.c 内にボス専用判断(例)
static int boss_hp_percent(const Enemy* b) {
return (b->hp * 100) / b->max_hp;
}
static void boss_take_turn(Enemy* boss, Character party[PARTY_SIZE], int turn) {
int hp = boss_hp_percent(boss);
/* 1) 周期ブレス:3ターンごとに全体攻撃(MPあるなら) */
if (turn % 3 == 0 && boss->mp >= boss->spells[0].mp_cost) {
boss_cast_dragon_breath(boss, party);
return;
}
/* 2) 強化が切れているなら自己強化(20%) */
if (boss->buff_atk_turns <= 0 && boss->mp >= boss->spells[1].mp_cost) {
if ((rand() % 100) < 20) {
boss_cast_ancient_roar(boss);
return;
}
}
/* 3) HP半分以下なら回復優先(35%) */
if (hp <= 50 && boss->mp >= boss->spells[2].mp_cost) {
if ((rand() % 100) < 35) {
cast_enemy_heal_spell(boss, 2); /* 既存の回復処理を流用する想定 */
return;
}
}
/* 4) 通常攻撃 */
enemy_attack_party(boss, party);
}map層:ボス部屋に到達したらボス戦へ
例:マップ最深部(座標 23,23)に到達したらボス戦開始。
if (player.x == 23 && player.y == 23) {
ui_message("A terrifying presence fills the air...");
int win = battle_boss_master_dragon(party);
if (win) {
/* エンディングへ */
} else {
/* 全滅処理(教会復活に戻す等) */
}
}ui層:撃破後のエンディング導入
STEP04でタイトル・エンディングを作っている前提で、ここでは
- 「勝利演出」→「世界が救われた」→「The End」
を短いテキストでつなげると良いです。
ui.h
void ui_show_ending_intro(void);
void ui_show_ending(void);ui.c(例)
void ui_show_ending_intro(void) {
clear_screen();
printf("The Master Dragon has fallen...\n");
printf("A warm light spreads across the land.\n");
printf("Your journey is finally over.\n");
wait_key();
}ボス勝利後に
ui_show_ending_intro();
ui_show_ending();で締めればOKです。
演習問題+模範解答例
演習:ボスの「怒りモード」を追加する
問題
マスタードラゴンのHPが25%以下になったら、毎ターン Dragon Breath を撃つ確率を 50% にしてください。
模範解答例(boss_take_turn 冒頭に追加)
int hp = boss_hp_percent(boss);
if (hp <= 25 && boss->mp >= boss->spells[0].mp_cost) {
if ((rand() % 100) < 50) {
boss_cast_dragon_breath(boss, party);
return;
}
}STEP13のまとめ
- ボスは「固定出現+専用テンプレート」で演出を作る。
- 専用魔法(全体攻撃/自己強化/大回復)で格の違いを出す。
- ボスAIは通常敵AIとは分けて「周期」「条件分岐」を入れると面白い。
- 撃破後にui層のエンディング導入へ接続して、物語を閉じる。
