cenotaph/src/stage.h
2026-02-17 17:40:34 -05:00

102 lines
3.1 KiB
C

struct LevelDef {
u8 drones, gunners, hunters, builders;
u8 bossHp;
u8 humans;
u8 gunnerPattern; // 0=radial, 1=aimed fan, 2=mix
bool dronesShoot;
};
// dr gn hn bl boss hum pat shoot
const struct LevelDef levels[30] = {
// Phase 1: "Immediate danger" (L1-L6)
{ 8, 1, 0, 0, 0, 8, 0, FALSE }, // L1
{ 10, 2, 0, 0, 0, 8, 0, TRUE }, // L2
{ 12, 2, 0, 0, 0, 8, 0, TRUE }, // L3
{ 10, 3, 0, 0, 0, 8, 1, TRUE }, // L4
{ 14, 3, 0, 0, 0, 8, 1, TRUE }, // L5
{ 8, 0, 0, 0, 8, 8, 0, TRUE }, // L6 BOSS
// Phase 2: "You can't save everything" (L7-L12)
{ 10, 0, 0, 1, 0, 8, 0, TRUE }, // L7
{ 10, 2, 0, 1, 0, 8, 0, TRUE }, // L8
{ 12, 0, 0, 2, 0, 8, 0, TRUE }, // L9
{ 14, 3, 0, 1, 0, 8, 1, TRUE }, // L10 WALL
{ 10, 2, 0, 2, 0, 8, 2, TRUE }, // L11
{ 8, 0, 0, 1, 12, 8, 0, TRUE }, // L12 BOSS
// Phase 3: "Geometry matters" (L13-L18)
{ 8, 0, 4, 0, 0, 8, 0, TRUE }, // L13
{ 8, 3, 2, 0, 0, 8, 1, TRUE }, // L14
{ 16, 0, 0, 0, 0, 8, 0, TRUE }, // L15 FARM
{ 10, 2, 4, 0, 0, 8, 2, TRUE }, // L16
{ 12, 3, 3, 0, 0, 8, 1, TRUE }, // L17
{ 0, 2, 2, 0, 15, 8, 2, TRUE }, // L18 BOSS
// Phase 4: "Suffocation" (L19-L24)
{ 12, 4, 0, 0, 0, 8, 2, TRUE }, // L19
{ 14, 4, 0, 2, 0, 8, 2, TRUE }, // L20 WALL
{ 10, 0, 6, 0, 0, 8, 0, TRUE }, // L21
{ 12, 4, 2, 0, 0, 8, 1, TRUE }, // L22
{ 14, 4, 0, 2, 0, 8, 2, TRUE }, // L23
{ 0, 3, 0, 1, 20, 8, 2, TRUE }, // L24 BOSS
// Phase 5: "Arcade cruelty" (L25-L30)
{ 16, 0, 4, 0, 0, 8, 0, TRUE }, // L25
{ 12, 6, 0, 0, 0, 8, 2, TRUE }, // L26
{ 14, 2, 4, 0, 0, 8, 1, TRUE }, // L27
{ 16, 4, 0, 2, 0, 8, 2, TRUE }, // L28
{ 6, 2, 2, 1, 10, 8, 2, TRUE }, // L29 MINI-BOSS
{ 4, 2, 2, 1, 30, 8, 2, TRUE }, // L30 FINAL
};
#define LEVEL_COUNT 30
static void distributeEnemies(u8 type, u8 count){
for(u8 i = 0; i < count; i++){
u8 zone = i % 4;
spawnEnemy(type, zone);
}
}
void loadLevel(u8 lvl){
if(lvl >= LEVEL_COUNT) lvl = LEVEL_COUNT - 1;
level = lvl;
const struct LevelDef* def = &levels[lvl];
distributeEnemies(ENEMY_TYPE_DRONE, def->drones);
distributeEnemies(ENEMY_TYPE_GUNNER, def->gunners);
distributeEnemies(ENEMY_TYPE_HUNTER, def->hunters);
distributeEnemies(ENEMY_TYPE_BUILDER, def->builders);
// set gunner pattern based on level def
for(s16 i = 0; i < ENEMY_COUNT; i++){
if(enemies[i].active && enemies[i].type == ENEMY_TYPE_GUNNER){
if(def->gunnerPattern == 2)
enemies[i].ints[0] = random() % 2;
else
enemies[i].ints[0] = def->gunnerPattern;
}
}
if(def->bossHp > 0){
pendingBossHp = def->bossHp;
spawnEnemy(ENEMY_TYPE_BOSS, 1);
}
// spawn humans
u8 humansToSpawn = def->humans;
for(u8 zone = 0; zone < 4 && humansToSpawn > 0; zone++){
u8 perZone = humansToSpawn >= 4 ? 2 : 1;
for(u8 h = 0; h < perZone && humansToSpawn > 0; h++){
spawnHuman(zone);
humansToSpawn--;
}
}
loadMap();
}
// legacy test stage
void loadStage(){
loadLevel(0);
}