joeylib2/examples/spacetaxi/stLevelCels.c

114 lines
4.9 KiB
C

// Space Taxi -- the cels a level's hook program can put on screen.
//
// Hook sprites are built from the level's own VIC bitmaps in whatever
// colour the hook gives them, and compiling one on the 65816 costs about
// half a second -- far too long to do the first time a cel appears mid-
// ride. So every level lists its cels up front, from the same hook
// tables the hook program reads (stHookTables.h): the offline baker turns
// the list into a pre-compiled bank (sprites/levelNN.spc) and the game
// compiles whatever the bank does not supply BEFORE the ride starts.
//
// Only the level file is needed, no simulation, so the baker can link
// this on the host without the rest of the game.
#include "stCels.h"
#include "stHookTables.h"
#define HKL(level, addr) ((level)->hookData[(addr) - ST_HOOK_BASE])
static void celAdd(StCelDefT *out, uint8_t *count, uint8_t max, uint8_t ptr, uint8_t color, uint8_t multi, uint8_t mc0, uint8_t mc1);
// Append one cel unless the list already has it.
static void celAdd(StCelDefT *out, uint8_t *count, uint8_t max, uint8_t ptr, uint8_t color, uint8_t multi, uint8_t mc0, uint8_t mc1) {
uint8_t k;
for (k = 0u; k < *count; k++) {
if (out[k].ptr == ptr && out[k].color == color && out[k].multi == multi && out[k].mc0 == mc0 && out[k].mc1 == mc1) {
return;
}
}
if (*count == max) {
return;
}
out[*count].ptr = ptr;
out[*count].color = color;
out[*count].multi = multi;
out[*count].mc0 = mc0;
out[*count].mc1 = mc1;
(*count)++;
}
uint8_t stLevelCelList(const StLevelT *level, StCelDefT *out, uint8_t max) {
uint8_t n = 0u;
uint8_t k;
uint8_t c;
switch (level->levelIndex) {
case ST_LEVEL_G:
for (k = 0u; k < ST_HK_G_CEL_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_G_CEL + k), ST_HK_G_ORB_COLOR, 0u, 0u, 0u);
}
break;
case ST_LEVEL_H:
celAdd(out, &n, max, ST_HK_H_CEL, ST_HK_H_COLOR_IDLE, 0u, 0u, 0u);
celAdd(out, &n, max, ST_HK_H_CEL, ST_HK_H_COLOR_LIT, 0u, 0u, 0u);
celAdd(out, &n, max, ST_HK_H_CEL, ST_HK_H_COLOR_ACTIVE, 0u, 0u, 0u);
break;
case ST_LEVEL_I:
// Every cel in the idle colour and in each of the three the
// launcher picks at random.
for (c = 0u; c <= ST_HK_I_COLORS; c++) {
uint8_t color = (c == 0u) ? ST_HK_I_COLOR_IDLE : HKL(level, ST_HK_I_COLOR + c - 1u);
for (k = 0u; k < ST_HK_I_RISE_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_I_CEL_RISE + k), color, 0u, 0u, 0u);
}
for (k = 0u; k < ST_HK_I_BURST_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_I_CEL_BURST + k), color, 0u, 0u, 0u);
}
}
break;
case ST_LEVEL_J:
celAdd(out, &n, max, ST_HK_FALL_CEL, ST_HK_J_COLOR, 0u, 0u, 0u);
celAdd(out, &n, max, (uint8_t)(ST_HK_FALL_CEL + 1u), ST_HK_J_COLOR, 0u, 0u, 0u);
celAdd(out, &n, max, ST_HK_FALL_CEL_BURST, ST_HK_J_COLOR, 0u, 0u, 0u);
for (k = 1u; k < ST_HK_J_BURST_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_J_CEL_BURST + k), ST_HK_J_COLOR, 0u, 0u, 0u);
}
break;
case ST_LEVEL_L:
for (k = ST_HK_L_CEL_FIRST; k < ST_HK_L_CEL_END; k++) {
celAdd(out, &n, max, k, ST_HK_L_COLOR, 0u, 0u, 0u);
}
break;
case ST_LEVEL_P:
celAdd(out, &n, max, ST_HK_FALL_CEL, ST_HK_P_COLOR, 0u, 0u, 0u);
celAdd(out, &n, max, (uint8_t)(ST_HK_FALL_CEL + 1u), ST_HK_P_COLOR, 0u, 0u, 0u);
celAdd(out, &n, max, ST_HK_FALL_CEL_BURST, ST_HK_P_COLOR, 0u, 0u, 0u);
for (k = 1u; k < ST_HK_P_BURST_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_P_CEL_BURST + k), ST_HK_P_COLOR, 0u, 0u, 0u);
}
break;
case ST_LEVEL_Q:
// The hook's cels show HIRES in colour 6 for the whole recorded
// ride (tools/stsim STSIM_CELS census, 2026-09-22); the
// multicolour variant (the level's own $D025/$D026) stays
// listed for the phases the census did not reach.
for (k = 0u; k < ST_HK_Q_CEL_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_Q_CEL + k), ST_HK_Q_COLOR, 0u, 0u, 0u);
}
for (k = 0u; k < ST_HK_Q_CEL_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_Q_CEL + k), ST_HK_Q_COLOR, 1u, level->header[5], level->header[6]);
}
break;
case ST_LEVEL_U:
for (k = 0u; k < ST_HK_U_CEL_PHASES; k++) {
celAdd(out, &n, max, HKL(level, ST_HK_U_CEL + k), ST_HK_U_COLOR, 0u, 0u, 0u);
}
break;
default:
break;
}
return n;
}