// 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; }