1001 lines
33 KiB
C
1001 lines
33 KiB
C
// Space Taxi -- per-level hook programs.
|
|
//
|
|
// Every level's data blob ends with six trampolines ($7D66..$7D77)
|
|
// and a small program at $7D98..$7FFF that the main loop calls at
|
|
// fixed points: two prelude hooks, two per-tick hooks (before and
|
|
// after the sprite flush), an input filter and the sprite-contact
|
|
// verdict. Those programs are the level gimmicks -- the puzzle
|
|
// switches, lasers, moving pads, trap doors. The port keeps the
|
|
// original bytes (sim->hookRam, for the tables the code indexes) and
|
|
// re-expresses each program here, reading its tables at the same
|
|
// addresses so nothing has to be transcribed by hand.
|
|
|
|
#include "stSim.h"
|
|
|
|
// Hook RAM accessors by C64 address.
|
|
#define HK(sim, addr) ((sim)->hookRam[(addr) - ST_HOOK_BASE])
|
|
#define HKP(sim, addr) (&(sim)->hookRam[(addr) - ST_HOOK_BASE])
|
|
|
|
// Level indices (0 = A).
|
|
#define ST_LEVEL_E 4u
|
|
#define ST_LEVEL_G 6u
|
|
#define ST_LEVEL_H 7u
|
|
#define ST_LEVEL_I 8u
|
|
#define ST_LEVEL_J 9u
|
|
#define ST_LEVEL_K 10u
|
|
#define ST_LEVEL_L 11u
|
|
#define ST_LEVEL_O 14u
|
|
#define ST_LEVEL_P 15u
|
|
#define ST_LEVEL_Q 16u
|
|
#define ST_LEVEL_R 17u
|
|
#define ST_LEVEL_T 19u
|
|
#define ST_LEVEL_U 20u
|
|
#define ST_LEVEL_V 21u
|
|
#define ST_LEVEL_W 22u
|
|
#define ST_LEVEL_X 23u
|
|
|
|
|
|
static void addToSpriteCol(StSimT *sim, uint8_t idx, uint8_t delta);
|
|
static void fillDownChar(StSimT *sim, uint8_t col, uint8_t row, uint8_t ch, uint8_t rows);
|
|
static void fillDownColor(StSimT *sim, uint8_t col, uint8_t row, uint8_t color, uint8_t rows);
|
|
static void hookHPerTick(StSimT *sim);
|
|
static void hookHPrelude0(StSimT *sim);
|
|
static void hookHSegment(StSimT *sim, uint8_t id);
|
|
static void hookTGate(StSimT *sim, uint8_t ch);
|
|
static void hookTPerTick(StSimT *sim);
|
|
static void hookTPrelude1(StSimT *sim);
|
|
static void hookWLaserUpdate(StSimT *sim);
|
|
static void hookWPerTick(StSimT *sim);
|
|
static void hookXMovePads(StSimT *sim);
|
|
static void hookXPerTick(StSimT *sim);
|
|
static void hookXPrelude0(StSimT *sim);
|
|
static void hookXShiftRow(StSimT *sim, uint16_t rowCell, uint8_t from, uint8_t to, int8_t dir);
|
|
static void setSpriteColors(StSimT *sim, uint8_t color);
|
|
#if !defined(__W65816__)
|
|
static void hookKPerTick(StSimT *sim);
|
|
static void hookOPerTick(StSimT *sim);
|
|
static void hookOTramp0(StSimT *sim);
|
|
static void hookRMaze(StSimT *sim, uint8_t ch);
|
|
static void hookRPerTick(StSimT *sim);
|
|
static void hookVPerTick(StSimT *sim);
|
|
static void hookVScrollLeft(StSimT *sim, uint8_t row);
|
|
static void hookVScrollRight(StSimT *sim, uint8_t row);
|
|
static void hookQPrelude(StSimT *sim);
|
|
static void hookQPerTick(StSimT *sim);
|
|
static uint8_t hookQInput(StSimT *sim, uint8_t input);
|
|
static void hookIPrelude(StSimT *sim);
|
|
static void hookIPerTick(StSimT *sim);
|
|
static void hookGPerTick(StSimT *sim);
|
|
static void hookUPerTick(StSimT *sim);
|
|
#endif
|
|
|
|
|
|
// $411B -- add a signed byte to a sprite's X (carry into the msb).
|
|
static void addToSpriteCol(StSimT *sim, uint8_t idx, uint8_t delta) {
|
|
uint16_t x = (uint16_t)(((uint16_t)sim->spr[idx].msb << 8) | sim->spr[idx].col);
|
|
|
|
x = (uint16_t)(x + (uint16_t)(int16_t)(int8_t)delta);
|
|
sim->spr[idx].col = (uint8_t)x;
|
|
sim->spr[idx].msb = (uint8_t)(x >> 8);
|
|
}
|
|
|
|
|
|
// $41AD after $401B -- the same character into the `rows` cells below.
|
|
static void fillDownChar(StSimT *sim, uint8_t col, uint8_t row, uint8_t ch, uint8_t rows) {
|
|
uint8_t k;
|
|
|
|
for (k = 1u; k <= rows; k++) {
|
|
if ((uint8_t)(row + k) < ST_SCREEN_ROWS) {
|
|
stSimPutChar(sim, col, (uint8_t)(row + k), ch);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// $41AD after $401E -- the same colour into the `rows` cells below.
|
|
static void fillDownColor(StSimT *sim, uint8_t col, uint8_t row, uint8_t color, uint8_t rows) {
|
|
uint8_t k;
|
|
|
|
for (k = 1u; k <= rows; k++) {
|
|
if ((uint8_t)(row + k) < ST_SCREEN_ROWS) {
|
|
stSimPutColor(sim, col, (uint8_t)(row + k), color);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Level H "PUZZLER" per-tick ($7E5A): touching a switch sprite, or
|
|
// landing on a pad whose list holds an active segment, animates the
|
|
// switch's four wall segments over four 8-tick steps with a rising
|
|
// tone, then toggles their flags.
|
|
static void hookHPerTick(StSimT *sim) {
|
|
if (HK(sim, 0x7E54) == 0u) {
|
|
if (sim->collisionPhase != 0u) {
|
|
return;
|
|
}
|
|
if (sim->activePad != 0u) {
|
|
uint8_t x = (uint8_t)((sim->activePad - 1u) * 4u);
|
|
uint8_t n;
|
|
bool found = false;
|
|
for (n = 0u; n < 4u; n++) {
|
|
uint8_t y = HK(sim, 0x7E24 + x + n);
|
|
if (HK(sim, 0x7E15 + y) != 0u) {
|
|
HK(sim, 0x7E4C) = y;
|
|
HK(sim, 0x7E54) = 6u;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
return;
|
|
}
|
|
} else {
|
|
uint8_t a = sim->spriteSpriteColl;
|
|
uint8_t y = 5u;
|
|
while (y != 0u) {
|
|
bool hit = (a & 0x80u) != 0u;
|
|
a = (uint8_t)(a << 1);
|
|
if (hit) {
|
|
break;
|
|
}
|
|
y--;
|
|
}
|
|
if (y == 0u) {
|
|
return;
|
|
}
|
|
HK(sim, 0x7E54) = y;
|
|
setSpriteColors(sim, 0x0Au);
|
|
sim->spr[2u + y].color = 0x05u;
|
|
}
|
|
// $7EB2: start the animation.
|
|
HK(sim, 0x7E53) = 0u;
|
|
HK(sim, 0x7E55) = 0xFFu;
|
|
HK(sim, 0x7E56) = 0x12u;
|
|
stAudioSfx(HKP(sim, 0x7ED0));
|
|
}
|
|
// $7ED9
|
|
HK(sim, 0x7E56)++;
|
|
stAudioVoice2(HK(sim, 0x7E56), HK(sim, 0x7E56), 0xFFu);
|
|
HK(sim, 0x7E53)++;
|
|
if ((HK(sim, 0x7E53) & 7u) != 0u) {
|
|
return;
|
|
}
|
|
HK(sim, 0x7E55)++;
|
|
HK(sim, 0x7E52) = (uint8_t)((HK(sim, 0x7E54) - 1u) * 4u);
|
|
HK(sim, 0x7E51) = 4u;
|
|
if (HK(sim, 0x7E55) == 4u) {
|
|
// $7F7C: finished -- flip the segment flags.
|
|
HK(sim, 0x7E54) = 0u;
|
|
setSpriteColors(sim, 0x01u);
|
|
while (HK(sim, 0x7E51) != 0u) {
|
|
uint8_t id = HK(sim, 0x7E38 + HK(sim, 0x7E52));
|
|
if ((id & 0x80u) == 0u) {
|
|
HK(sim, 0x7E15 + id) ^= 1u;
|
|
}
|
|
HK(sim, 0x7E52)++;
|
|
HK(sim, 0x7E51)--;
|
|
}
|
|
return;
|
|
}
|
|
while (HK(sim, 0x7E51) != 0u) {
|
|
uint8_t id = HK(sim, 0x7E38 + HK(sim, 0x7E52));
|
|
if ((id & 0x80u) == 0u) {
|
|
hookHSegment(sim, id);
|
|
}
|
|
HK(sim, 0x7E52)++;
|
|
HK(sim, 0x7E51)--;
|
|
}
|
|
}
|
|
|
|
|
|
// Level H prelude 0 ($7D9B): clear the segment flags, park the five
|
|
// switch sprites (3..7) from the position tables.
|
|
static void hookHPrelude0(StSimT *sim) {
|
|
uint8_t k;
|
|
|
|
for (k = 0u; k <= 10u; k++) {
|
|
HK(sim, 0x7E15 + k) = 0u;
|
|
}
|
|
HK(sim, 0x7E54) = 0u;
|
|
for (k = 7u; k >= 3u; k--) {
|
|
sim->spr[k].color = 1u;
|
|
sim->spr[k].enable = 1u;
|
|
sim->spr[k].ptr = 0x80u;
|
|
sim->spr[k].col = HK(sim, 0x7DCF + k);
|
|
sim->spr[k].msb = HK(sim, 0x7DD7 + k);
|
|
sim->spr[k].row = HK(sim, 0x7DDF + k);
|
|
}
|
|
}
|
|
|
|
|
|
// $7F22 -- draw (or erase) one cell of segment `id` for the current
|
|
// animation step, growing from whichever end the tables say.
|
|
static void hookHSegment(StSimT *sim, uint8_t id) {
|
|
uint8_t step;
|
|
uint8_t col;
|
|
uint8_t row;
|
|
uint8_t ch;
|
|
|
|
HK(sim, 0x7E50) = id;
|
|
if ((HK(sim, 0x7E15 + id) ^ HK(sim, 0x7DFD + id)) == 0u) {
|
|
step = HK(sim, 0x7E55);
|
|
} else {
|
|
step = (uint8_t)(3u - HK(sim, 0x7E55));
|
|
}
|
|
if (HK(sim, 0x7E08 + id) == 0x9Bu) {
|
|
row = (uint8_t)(step + HK(sim, 0x7DF2 + id));
|
|
col = HK(sim, 0x7DE7 + id);
|
|
} else {
|
|
col = (uint8_t)(step + HK(sim, 0x7DE7 + id));
|
|
row = HK(sim, 0x7DF2 + id);
|
|
}
|
|
HK(sim, 0x7E13) = col;
|
|
HK(sim, 0x7E14) = row;
|
|
ch = (HK(sim, 0x7E15 + id) != 0u) ? HK(sim, 0x7E08 + id) : ST_CHAR_SPACE;
|
|
stSimPutChar(sim, col, row, ch);
|
|
}
|
|
|
|
|
|
// Level T "FAST BREAK" $7D9D -- the barrier on row 3: `ch` into the
|
|
// centre opening (cols 18..21), its complement into the side gaps.
|
|
static void hookTGate(StSimT *sim, uint8_t ch) {
|
|
uint8_t k;
|
|
|
|
for (k = 0u; k < 4u; k++) {
|
|
stSimPutChar(sim, (uint8_t)(18u + k), 3u, ch);
|
|
}
|
|
ch ^= 0x55u;
|
|
for (k = 0u; k < 4u; k++) {
|
|
stSimPutChar(sim, (uint8_t)(1u + k), 3u, ch);
|
|
stSimPutChar(sim, (uint8_t)(35u + k), 3u, ch);
|
|
}
|
|
}
|
|
|
|
|
|
// Level T per-tick ($7DDA): a slow cab up on the right bounces off
|
|
// the ceiling; a fast climb into the top rows slams the centre gate
|
|
// shut and opens the sides until the cab drops back down.
|
|
static void hookTPerTick(StSimT *sim) {
|
|
if (HK(sim, 0x7D9C) != 0u) {
|
|
if (sim->spr[0].row >= 0x5Fu) {
|
|
hookTPrelude1(sim);
|
|
}
|
|
return;
|
|
}
|
|
if (sim->spr[0].row >= 0x4Fu) {
|
|
return;
|
|
}
|
|
if ((uint8_t)((uint16_t)sim->velY >> 8) >= 0xFCu) {
|
|
if (sim->spr[0].msb != 0u) {
|
|
return;
|
|
}
|
|
if (sim->spr[0].col < 0x96u) {
|
|
return;
|
|
}
|
|
sim->velY = (int16_t)(-sim->velY);
|
|
stAudioSfx(HKP(sim, 0x7E56));
|
|
return;
|
|
}
|
|
if (sim->spr[0].row >= 0x3Fu) {
|
|
return;
|
|
}
|
|
sim->velY = 0;
|
|
sim->velX = 0;
|
|
hookTGate(sim, 0x75u);
|
|
HK(sim, 0x7D9C)++;
|
|
stAudioSfx(HKP(sim, 0x7E68));
|
|
}
|
|
|
|
|
|
// Level T prelude 1 ($7DC4): centre open, sides barred.
|
|
static void hookTPrelude1(StSimT *sim) {
|
|
hookTGate(sim, ST_CHAR_SPACE);
|
|
HK(sim, 0x7D9C) = 0u;
|
|
stAudioSfx(HKP(sim, 0x7E5F));
|
|
}
|
|
|
|
|
|
// Level W "LASERS" $7E46 -- clear the beam glyphs, then step each of
|
|
// the eight lasers: idle ones fire on a 2-in-12 roll, extending ones
|
|
// grow a cell per pass until their end row, retracting ones fade
|
|
// through two colours and vanish.
|
|
static void hookWLaserUpdate(StSimT *sim) {
|
|
uint8_t i;
|
|
uint8_t k;
|
|
|
|
for (k = 0u; k < 16u; k++) {
|
|
sim->charset[0x92u + (k >> 3)][k & 7u] = 0u;
|
|
}
|
|
sim->charDirty[0x92u] = 1u;
|
|
sim->charDirty[0x93u] = 1u;
|
|
for (i = 0u; i < 8u; i++) {
|
|
uint8_t state = HK(sim, 0x7DAC + i);
|
|
uint8_t col = HK(sim, 0x7DCD + i);
|
|
HK(sim, 0x7DB4) = i;
|
|
if (state == 0u) {
|
|
if (stSimRng(sim, 12u) >= 3u) {
|
|
continue;
|
|
}
|
|
HK(sim, 0x7DAC + i) = 1u;
|
|
HK(sim, 0x7DB5 + i) = HK(sim, 0x7DD5 + i);
|
|
stSimPutChar(sim, col, HK(sim, 0x7DB5 + i), HK(sim, 0x7DBD + i));
|
|
stSimPutColor(sim, col, HK(sim, 0x7DB5 + i), 2u);
|
|
continue;
|
|
}
|
|
if (state == 1u) {
|
|
stSimPutChar(sim, col, HK(sim, 0x7DB5 + i), 0x91u);
|
|
if (HK(sim, 0x7DB5 + i) == HK(sim, 0x7DE9 + i)) {
|
|
HK(sim, 0x7DAC + i) = 2u;
|
|
HK(sim, 0x7DB5 + i) = 0u;
|
|
state = 2u;
|
|
} else {
|
|
HK(sim, 0x7DB5 + i) = (uint8_t)(HK(sim, 0x7DB5 + i) + HK(sim, 0x7DDD + i));
|
|
stSimPutChar(sim, col, HK(sim, 0x7DB5 + i), HK(sim, 0x7DBD + i));
|
|
stSimPutColor(sim, col, HK(sim, 0x7DB5 + i), 2u);
|
|
continue;
|
|
}
|
|
}
|
|
if (state == 2u) {
|
|
uint8_t phase;
|
|
HK(sim, 0x7DB5 + i)++;
|
|
phase = HK(sim, 0x7DB5 + i);
|
|
if (phase == 3u) {
|
|
HK(sim, 0x7DAC + i) = 0u;
|
|
stSimPutChar(sim, col, HK(sim, 0x7DC5 + i), ST_CHAR_SPACE);
|
|
fillDownChar(sim, col, HK(sim, 0x7DC5 + i), ST_CHAR_SPACE, 7u);
|
|
} else {
|
|
uint8_t color = HK(sim, 0x7DE6 + phase);
|
|
stSimPutColor(sim, col, HK(sim, 0x7DC5 + i), color);
|
|
fillDownColor(sim, col, HK(sim, 0x7DC5 + i), color, 7u);
|
|
}
|
|
continue;
|
|
}
|
|
HK(sim, 0x7DAC + i) = 0u;
|
|
}
|
|
}
|
|
|
|
|
|
// Level W per-tick ($7DF1): a random-pitched hum on voice 2, the beam
|
|
// glyph animation on the odd ticks and the laser step on every 8th.
|
|
static void hookWPerTick(StSimT *sim) {
|
|
for (;;) {
|
|
uint8_t c;
|
|
if (HK(sim, 0x7DE5) != 0u) {
|
|
stAudioSfx(HKP(sim, 0x7DA2));
|
|
HK(sim, 0x7DE5) = 0u;
|
|
}
|
|
c = (uint8_t)(stSimRng(sim, 0x6Eu) + 6u);
|
|
stAudioVoice2(c, c, 0x81u);
|
|
HK(sim, 0x7DAB) = (uint8_t)((HK(sim, 0x7DAB) + 1u) & 7u);
|
|
c = HK(sim, 0x7DAB);
|
|
if (c == 0u) {
|
|
hookWLaserUpdate(sim);
|
|
return;
|
|
}
|
|
// $2C8F + c (char $91 row 7 for c = 0, else char $92 rows 0..6)
|
|
// and $2C98 + (8 - c) (char $93 rows 7..1) get a beam bar.
|
|
sim->charset[0x91u + ((7u + c) >> 3)][(7u + c) & 7u] = 0x3Cu;
|
|
sim->charset[0x93u][8u - c] = 0x3Cu;
|
|
sim->charDirty[0x92u] = 1u;
|
|
sim->charDirty[0x93u] = 1u;
|
|
if ((c & 1u) == 0u) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Level X "ON THE MOVE" $7F53 -- shift every pad's X bounds and stand
|
|
// column, the waiting passenger, and a parked cab, by the step.
|
|
static void hookXMovePads(StSimT *sim) {
|
|
uint8_t dir = HK(sim, 0x7D9D);
|
|
uint8_t off = 0u;
|
|
uint8_t phase = 0u;
|
|
|
|
addToSpriteCol(sim, 1u, dir);
|
|
while (off < 0x48u) {
|
|
uint8_t pad = (uint8_t)(off >> 3);
|
|
uint8_t field = (uint8_t)(off & 7u);
|
|
uint8_t *hi;
|
|
uint8_t *lo;
|
|
uint16_t v;
|
|
if (field == 0u) {
|
|
hi = &sim->pads[pad].x1Hi;
|
|
lo = &sim->pads[pad].x1Lo;
|
|
} else if (field == 2u) {
|
|
hi = &sim->pads[pad].x2Hi;
|
|
lo = &sim->pads[pad].x2Lo;
|
|
} else {
|
|
hi = &sim->pads[pad].passMsb;
|
|
lo = &sim->pads[pad].passCol;
|
|
}
|
|
v = (uint16_t)(((uint16_t)*hi << 8) | *lo);
|
|
v = (uint16_t)(v + (uint16_t)(int16_t)(int8_t)dir);
|
|
*lo = (uint8_t)v;
|
|
*hi = (uint8_t)(v >> 8);
|
|
// Offsets step +2, +3, +3 repeating: x1, x2, stand X per pad.
|
|
if (phase == 0u) {
|
|
off = (uint8_t)(off + 2u);
|
|
} else {
|
|
off = (uint8_t)(off + 3u);
|
|
}
|
|
phase = (uint8_t)((phase + 1u) % 3u);
|
|
}
|
|
if (sim->activePad == 0u) {
|
|
return;
|
|
}
|
|
addToSpriteCol(sim, 0u, dir);
|
|
sim->posXmsb = sim->spr[0].msb;
|
|
sim->hoverXFrac = sim->spr[0].msb;
|
|
sim->posXcol = sim->spr[0].col;
|
|
sim->hoverXCol = sim->spr[0].col;
|
|
}
|
|
|
|
|
|
// Level X per-tick ($7DE1): every 16 ticks slide the two pad columns
|
|
// one cell, bouncing between columns 1 and 21.
|
|
static void hookXPerTick(StSimT *sim) {
|
|
uint8_t col;
|
|
|
|
HK(sim, 0x7D9E)++;
|
|
if (HK(sim, 0x7D9E) != 0x10u) {
|
|
return;
|
|
}
|
|
HK(sim, 0x7D9E) = 0u;
|
|
col = HK(sim, 0x7D9C);
|
|
if ((HK(sim, 0x7D9D) & 0x80u) == 0u) {
|
|
// $7DF9: rightward.
|
|
hookXShiftRow(sim, ST_CELL(5, 0), (uint8_t)(col + 17u), col, 1);
|
|
hookXShiftRow(sim, ST_CELL(10, 0), (uint8_t)(col + 17u), col, 1);
|
|
hookXShiftRow(sim, ST_CELL(15, 0), (uint8_t)(col + 17u), col, 1);
|
|
hookXShiftRow(sim, ST_CELL(20, 0), (uint8_t)(col + 17u), col, 1);
|
|
stSimPutChar(sim, col, 5u, HK(sim, 0x7D9F + col));
|
|
stSimPutChar(sim, col, 10u, HK(sim, 0x7D9F + col));
|
|
stSimPutChar(sim, col, 15u, HK(sim, 0x7D9F + col));
|
|
stSimPutChar(sim, col, 20u, HK(sim, 0x7D9F + col));
|
|
stSimPutColor(sim, col, 5u, 0x0Cu);
|
|
stSimPutColor(sim, col, 10u, 0x0Cu);
|
|
stSimPutColor(sim, col, 15u, 0x0Cu);
|
|
stSimPutColor(sim, col, 20u, 0x0Cu);
|
|
// $7E56: the row-14 cell of the right group moves with it.
|
|
stSimPutChar(sim, (uint8_t)(col + 12u), 14u, sim->screen[ST_CELL(14, col + 11u)]);
|
|
stSimPutChar(sim, (uint8_t)(col + 11u), 14u, ST_CHAR_SPACE);
|
|
stSimPutColor(sim, (uint8_t)(col + 12u), 14u, 7u);
|
|
stSimPutChar(sim, (uint8_t)(col + 11u), 5u, HK(sim, 0x7D9F + col + 11u));
|
|
stSimPutChar(sim, (uint8_t)(col + 11u), 10u, HK(sim, 0x7D9F + col + 11u));
|
|
stSimPutChar(sim, (uint8_t)(col + 11u), 15u, HK(sim, 0x7D9F + col + 11u));
|
|
stSimPutChar(sim, (uint8_t)(col + 11u), 20u, HK(sim, 0x7D9F + col + 11u));
|
|
stSimPutColor(sim, (uint8_t)(col + 11u), 5u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 11u), 10u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 11u), 15u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 11u), 20u, 0x0Cu);
|
|
hookXMovePads(sim);
|
|
HK(sim, 0x7D9C)++;
|
|
if (HK(sim, 0x7D9C) == 0x15u) {
|
|
HK(sim, 0x7D9D) = 0xF8u;
|
|
}
|
|
return;
|
|
}
|
|
// $7E9E: leftward.
|
|
hookXShiftRow(sim, ST_CELL(5, 0), col, (uint8_t)(col + 17u), -1);
|
|
hookXShiftRow(sim, ST_CELL(10, 0), col, (uint8_t)(col + 17u), -1);
|
|
hookXShiftRow(sim, ST_CELL(15, 0), col, (uint8_t)(col + 17u), -1);
|
|
hookXShiftRow(sim, ST_CELL(20, 0), col, (uint8_t)(col + 17u), -1);
|
|
stSimPutChar(sim, (uint8_t)(col + 6u), 5u, HK(sim, 0x7D9F + col + 6u));
|
|
stSimPutChar(sim, (uint8_t)(col + 6u), 10u, HK(sim, 0x7D9F + col + 6u));
|
|
stSimPutChar(sim, (uint8_t)(col + 6u), 15u, HK(sim, 0x7D9F + col + 6u));
|
|
stSimPutChar(sim, (uint8_t)(col + 6u), 20u, HK(sim, 0x7D9F + col + 6u));
|
|
stSimPutColor(sim, (uint8_t)(col + 6u), 5u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 6u), 10u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 6u), 15u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 6u), 20u, 0x0Cu);
|
|
stSimPutChar(sim, (uint8_t)(col + 10u), 14u, sim->screen[ST_CELL(14, col + 11u)]);
|
|
stSimPutChar(sim, (uint8_t)(col + 11u), 14u, ST_CHAR_SPACE);
|
|
stSimPutColor(sim, (uint8_t)(col + 10u), 14u, 7u);
|
|
stSimPutChar(sim, (uint8_t)(col + 17u), 5u, HK(sim, 0x7D9F + col + 17u));
|
|
stSimPutChar(sim, (uint8_t)(col + 17u), 10u, HK(sim, 0x7D9F + col + 17u));
|
|
stSimPutChar(sim, (uint8_t)(col + 17u), 15u, HK(sim, 0x7D9F + col + 17u));
|
|
stSimPutChar(sim, (uint8_t)(col + 17u), 20u, HK(sim, 0x7D9F + col + 17u));
|
|
stSimPutColor(sim, (uint8_t)(col + 17u), 5u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 17u), 10u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 17u), 15u, 0x0Cu);
|
|
stSimPutColor(sim, (uint8_t)(col + 17u), 20u, 0x0Cu);
|
|
hookXMovePads(sim);
|
|
HK(sim, 0x7D9C)--;
|
|
if (HK(sim, 0x7D9C) == 1u) {
|
|
HK(sim, 0x7D9D) = 0x08u;
|
|
}
|
|
}
|
|
|
|
|
|
// Level X prelude 0 ($7DC6): reset the sweep and restore the pad table
|
|
// from the level's backup copy ($7FB8).
|
|
static void hookXPrelude0(StSimT *sim) {
|
|
uint8_t k;
|
|
|
|
HK(sim, 0x7D9D) = 0xF8u;
|
|
HK(sim, 0x7D9C) = 0x0Bu;
|
|
HK(sim, 0x7D9E) = 0u;
|
|
for (k = 0u; k < 8u; k++) {
|
|
const uint8_t *src = HKP(sim, 0x7FB8 + k * 8u);
|
|
sim->pads[k].x1Hi = src[0];
|
|
sim->pads[k].x1Lo = src[1];
|
|
sim->pads[k].x2Hi = src[2];
|
|
sim->pads[k].x2Lo = src[3];
|
|
sim->pads[k].row = src[4];
|
|
sim->pads[k].passMsb = src[5];
|
|
sim->pads[k].passCol = src[6];
|
|
sim->pads[k].unused = src[7];
|
|
}
|
|
}
|
|
|
|
|
|
// Copy cells of one screen row (char + colour) one column along, from
|
|
// column `from` to column `to` inclusive, in the direction that keeps
|
|
// the copy from overwriting its own source.
|
|
static void hookXShiftRow(StSimT *sim, uint16_t rowCell, uint8_t from, uint8_t to, int8_t dir) {
|
|
uint8_t x = from;
|
|
|
|
for (;;) {
|
|
uint16_t src = (uint16_t)(rowCell + x);
|
|
uint16_t dst = (uint16_t)(src + (uint16_t)(int16_t)dir);
|
|
stSimPutChar(sim, (uint8_t)(dst % ST_SCREEN_COLS), (uint8_t)(dst / ST_SCREEN_COLS), sim->screen[src]);
|
|
stSimPutColor(sim, (uint8_t)(dst % ST_SCREEN_COLS), (uint8_t)(dst / ST_SCREEN_COLS), sim->color[src]);
|
|
if (x == to) {
|
|
break;
|
|
}
|
|
x = (uint8_t)(x - (uint8_t)dir);
|
|
}
|
|
}
|
|
|
|
|
|
// Sprites 3..7 share one colour in the puzzle level.
|
|
static void setSpriteColors(StSimT *sim, uint8_t color) {
|
|
uint8_t k;
|
|
|
|
for (k = 3u; k < ST_HW_SPRITES; k++) {
|
|
sim->spr[k].color = color;
|
|
}
|
|
}
|
|
|
|
|
|
// Extra-level gimmicks (magnets, electroids, maze, shift-o-rama,
|
|
// interference, crossfire, teleports, rebound). Compiled out on the
|
|
// IIgs, whose bank-0 BSS/text budget is too tight for them; those
|
|
// levels play without their hazard there (the 4 attract-demo levels
|
|
// H/T/W/X keep their gimmicks everywhere).
|
|
#if !defined(__W65816__)
|
|
// Level K "MAGNETS" per-tick ($7D9D): the level is globally anti-gravity
|
|
// (its yGrav template is -7); the hook only animates the six magnet
|
|
// poles by flipping bit 0 of their glyphs every other tick.
|
|
static void hookKPerTick(StSimT *sim) {
|
|
static const uint8_t kPole[6] = { 0x04u, 0x0Bu, 0x10u, 0x17u, 0x1Cu, 0x23u };
|
|
uint8_t k;
|
|
|
|
HK(sim, 0x7DBD) ^= 1u;
|
|
if ((HK(sim, 0x7DBD) & 1u) != 0u) {
|
|
return;
|
|
}
|
|
for (k = 0u; k < 6u; k++) {
|
|
uint16_t cell = (uint16_t)(0xA0u + kPole[k]); // $04A0 + off
|
|
stSimPutChar(sim, (uint8_t)(cell % ST_SCREEN_COLS), (uint8_t)(cell / ST_SCREEN_COLS), (uint8_t)(sim->screen[cell] ^ 1u));
|
|
}
|
|
}
|
|
|
|
|
|
// Level O "ELECTROIDS" per-tick ($7DBE): four electric barriers (rows
|
|
// 5, 14, 22, 26 of screen RAM in cell terms) scroll left one column,
|
|
// the leftmost cell wrapping to the right, at a rate gated by a mod-8
|
|
// tick (rows 1-2 every tick, row 3 every 4th).
|
|
static void hookOScrollRow(StSimT *sim, uint16_t base) {
|
|
uint8_t chSave = sim->screen[base];
|
|
uint8_t colSave = sim->color[base];
|
|
uint8_t x;
|
|
uint16_t cell;
|
|
|
|
for (x = 1u; x < 0x26u; x++) {
|
|
cell = (uint16_t)(base + x);
|
|
stSimPutChar(sim, (uint8_t)((base + x - 1u) % ST_SCREEN_COLS), (uint8_t)((base + x - 1u) / ST_SCREEN_COLS), sim->screen[cell]);
|
|
stSimPutColor(sim, (uint8_t)((base + x - 1u) % ST_SCREEN_COLS), (uint8_t)((base + x - 1u) / ST_SCREEN_COLS), sim->color[cell]);
|
|
}
|
|
cell = (uint16_t)(base + 0x25u);
|
|
stSimPutChar(sim, (uint8_t)(cell % ST_SCREEN_COLS), (uint8_t)(cell / ST_SCREEN_COLS), chSave);
|
|
stSimPutColor(sim, (uint8_t)(cell % ST_SCREEN_COLS), (uint8_t)(cell / ST_SCREEN_COLS), colSave);
|
|
}
|
|
|
|
|
|
static void hookOPerTick(StSimT *sim) {
|
|
hookOTramp0(sim); // $7E6E bitScroll of the barrier glyph
|
|
HK(sim, 0x7DBD) = (uint8_t)((HK(sim, 0x7DBD) + 1u) & 7u);
|
|
if ((HK(sim, 0x7DBD) & 3u) != 0u) {
|
|
return;
|
|
}
|
|
hookOScrollRow(sim, 0xC9u); // $04C9 row 5 col 1
|
|
hookOScrollRow(sim, 0x209u); // $0609 row 12 col 1
|
|
if (HK(sim, 0x7DBD) != 4u) {
|
|
return;
|
|
}
|
|
hookOScrollRow(sim, 0x169u); // $0569 row 9 col 1
|
|
hookOScrollRow(sim, 0x2A9u); // $06A9 row 17 col 1
|
|
}
|
|
|
|
|
|
// $63D0-style rotate of the two electroid glyphs ($2BE0 / char $6F).
|
|
static void hookOTramp0(StSimT *sim) {
|
|
uint8_t k;
|
|
|
|
for (k = 0u; k < 8u; k++) {
|
|
uint8_t b = sim->charset[0x6Fu][k];
|
|
sim->charset[0x6Fu][k] = (uint8_t)((b >> 1) | (b << 7));
|
|
}
|
|
sim->charDirty[0x6Fu] = 1u;
|
|
}
|
|
|
|
|
|
// Level R "TAXI MAZE" wall program ($7D9C): put `ch` in the vertical
|
|
// bar cells ($043E/$0466/$048E) and its complement (ch^$46) in the
|
|
// gate cells; called with $66 to close, with the gate's own char to
|
|
// flip. Toggling on pickup opens a path.
|
|
static void hookRMaze(StSimT *sim, uint8_t ch) {
|
|
static const uint16_t kBar[3] = { 0x3Eu, 0x66u, 0x8Eu };
|
|
static const uint16_t kGate[10] = { 0x39u, 0x61u, 0x89u, 0xA1u, 0xA2u, 0xA3u, 0xA4u, 0x309u, 0x30Au, 0x30Bu };
|
|
uint8_t k;
|
|
uint8_t alt = (uint8_t)(ch ^ 0x46u);
|
|
|
|
for (k = 0u; k < 3u; k++) {
|
|
stSimPutChar(sim, (uint8_t)(kBar[k] % ST_SCREEN_COLS), (uint8_t)(kBar[k] / ST_SCREEN_COLS), ch);
|
|
}
|
|
for (k = 0u; k < 10u; k++) {
|
|
stSimPutChar(sim, (uint8_t)(kGate[k] % ST_SCREEN_COLS), (uint8_t)(kGate[k] / ST_SCREEN_COLS), alt);
|
|
}
|
|
}
|
|
|
|
|
|
// Level R per-tick ($7DD2): when the passenger boards (stage 4) and the
|
|
// gate is open ($0439 == space) the maze flips.
|
|
static void hookRPerTick(StSimT *sim) {
|
|
if (sim->stage != ST_STAGE_BOARD) {
|
|
return;
|
|
}
|
|
if (sim->screen[0x39u] != ST_CHAR_SPACE) {
|
|
return;
|
|
}
|
|
hookRMaze(sim, sim->screen[0x39u]);
|
|
}
|
|
|
|
|
|
// Level V "SHIFT-O-RAMA" per-tick ($7D9D): every screen tick, 18 rows
|
|
// (0..17) each scroll one column, alternating direction by row (bit 1
|
|
// of the row index): even-band rows left, odd-band right, the edge
|
|
// cell wrapping around.
|
|
static void hookVScrollLeft(StSimT *sim, uint8_t row) {
|
|
uint16_t base = ST_CELL(row, 0);
|
|
uint8_t chSave = sim->screen[base];
|
|
uint8_t colSave = sim->color[base];
|
|
uint8_t x;
|
|
|
|
for (x = 1u; x < 0x27u; x++) {
|
|
stSimPutChar(sim, (uint8_t)(x - 1u), row, sim->screen[base + x]);
|
|
stSimPutColor(sim, (uint8_t)(x - 1u), row, sim->color[base + x]);
|
|
}
|
|
stSimPutChar(sim, 0x26u, row, chSave);
|
|
stSimPutColor(sim, 0x26u, row, colSave);
|
|
}
|
|
|
|
|
|
static void hookVScrollRight(StSimT *sim, uint8_t row) {
|
|
uint16_t base = ST_CELL(row, 0);
|
|
uint8_t chSave = sim->screen[base + 0x26u];
|
|
uint8_t colSave = sim->color[base + 0x26u];
|
|
uint8_t x;
|
|
|
|
for (x = 0x26u; x > 0u; x--) {
|
|
stSimPutChar(sim, x, row, sim->screen[base + x - 1u]);
|
|
stSimPutColor(sim, x, row, sim->color[base + x - 1u]);
|
|
}
|
|
stSimPutChar(sim, 0u, row, chSave);
|
|
stSimPutColor(sim, 0u, row, colSave);
|
|
}
|
|
|
|
|
|
static void hookVPerTick(StSimT *sim) {
|
|
uint8_t row;
|
|
|
|
for (row = 6u; row < 0x12u; row++) {
|
|
if ((row & 2u) != 0u) {
|
|
hookVScrollLeft(sim, row);
|
|
} else {
|
|
hookVScrollRight(sim, row);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Level Q "INTERFERENCE" ($7DA1 prelude0, $7E0D per-tick2, $7E2E input):
|
|
// five interference sprites (hw 3..7) sit at fixed spots flickering
|
|
// through cels $80..$8B, and while the cab is mid-screen the joystick
|
|
// is scrambled 20% of ticks.
|
|
static void hookQPrelude(StSimT *sim) {
|
|
int8_t x;
|
|
|
|
sim->multiColorMask = 0xFFu;
|
|
for (x = 7; x >= 3; x--) {
|
|
HK(sim, 0x7E83 + (uint8_t)x) = HK(sim, 0x7DEA + (uint8_t)x);
|
|
sim->spr[x].ptr = HK(sim, 0x7DF2 + HK(sim, 0x7E83 + (uint8_t)x));
|
|
sim->spr[x].color = 0x06u;
|
|
sim->spr[x].col = HK(sim, 0x7DD2 + (uint8_t)x);
|
|
sim->spr[x].msb = HK(sim, 0x7DDA + (uint8_t)x);
|
|
sim->spr[x].row = HK(sim, 0x7DE2 + (uint8_t)x);
|
|
sim->spr[x].enable = 1u;
|
|
}
|
|
}
|
|
|
|
|
|
static void hookQPerTick(StSimT *sim) {
|
|
int8_t x;
|
|
|
|
for (x = 7; x >= 3; x--) {
|
|
HK(sim, 0x7E83 + (uint8_t)x)++;
|
|
if (HK(sim, 0x7E83 + (uint8_t)x) == 0x0Cu) {
|
|
HK(sim, 0x7E83 + (uint8_t)x) = 0u;
|
|
}
|
|
sim->spr[x].ptr = HK(sim, 0x7DF2 + HK(sim, 0x7E83 + (uint8_t)x));
|
|
}
|
|
}
|
|
|
|
|
|
static uint8_t hookQInput(StSimT *sim, uint8_t input) {
|
|
if (sim->activePad != 0u) {
|
|
return input;
|
|
}
|
|
if (sim->spr[0].row < 0x5Au || sim->spr[0].row >= 0xB4u) {
|
|
return input;
|
|
}
|
|
if (stSimRng(sim, 10u) < 8u) {
|
|
return input;
|
|
}
|
|
return HK(sim, 0x7E7F + (uint8_t)(stSimRng(sim, 4u) - 1u));
|
|
}
|
|
|
|
|
|
// Level I "CROSSFIRE" ($7D9C prelude0, $7DEF per-tick2, $7DB1 prelude1):
|
|
// bullets (hw 3..7) fly up from the floor, cel-walk, then burst.
|
|
static void hookIPrelude(StSimT *sim) {
|
|
int8_t x;
|
|
|
|
for (x = 7; x >= 3; x--) {
|
|
HK(sim, 0x7DB8 + (uint8_t)x) = 0u; // state
|
|
sim->spr[x].enable = 0u;
|
|
sim->spr[x].color = 0x02u;
|
|
}
|
|
}
|
|
|
|
|
|
static void hookIPerTick(StSimT *sim) {
|
|
int8_t s;
|
|
|
|
for (s = 3; s <= 7; s++) {
|
|
uint8_t x = (uint8_t)s;
|
|
uint8_t state = HK(sim, 0x7DB8 + x);
|
|
if (state == 0u) {
|
|
uint8_t y;
|
|
if (stSimRng(sim, 0x75u) >= 3u) {
|
|
continue;
|
|
}
|
|
y = (uint8_t)(stSimRng(sim, 4u) - 1u); // 0..3 direction
|
|
HK(sim, 0x7DC8 + x) = HK(sim, 0x7DE1 + y); // dx
|
|
sim->spr[x].col = HK(sim, 0x7DDD + y); // start col
|
|
sim->spr[x].msb = 0u;
|
|
sim->spr[x].row = 0xD1u;
|
|
HK(sim, 0x7DD0 + x) = (uint8_t)(stSimRng(sim, 2u) + 0xFDu); // dy = rng(2)-3
|
|
HK(sim, 0x7DC0 + x) = 0u; // cel phase
|
|
HK(sim, 0x7DB8 + x) = 1u;
|
|
sim->spr[x].enable = 1u;
|
|
sim->spr[x].ptr = 0x84u;
|
|
stAudioSfx(HKP(sim, 0x7E82));
|
|
sim->spr[x].color = HK(sim, 0x7E7F + (uint8_t)(stSimRng(sim, 3u) - 1u));
|
|
} else if (state == 1u) {
|
|
uint8_t ph = (uint8_t)(HK(sim, 0x7DC0 + x) + 1u);
|
|
HK(sim, 0x7DC0 + x) = ph;
|
|
if (ph == 5u) {
|
|
HK(sim, 0x7DC0 + x) = 0u;
|
|
sim->spr[x].ptr = 0x85u;
|
|
HK(sim, 0x7DB8 + x) = 2u;
|
|
} else {
|
|
if (ph >= 3u) {
|
|
addToSpriteCol(sim, x, HK(sim, 0x7DC8 + x));
|
|
sim->spr[x].row = (uint8_t)(sim->spr[x].row + HK(sim, 0x7DD0 + x));
|
|
}
|
|
sim->spr[x].ptr = HK(sim, 0x7DD8 + ph);
|
|
}
|
|
} else {
|
|
uint8_t ph = (uint8_t)((HK(sim, 0x7DC0 + x) + 1u) & 7u);
|
|
HK(sim, 0x7DC0 + x) = ph;
|
|
sim->spr[x].ptr = HK(sim, 0x7DE5 + ph);
|
|
addToSpriteCol(sim, x, HK(sim, 0x7DC8 + x));
|
|
sim->spr[x].row = (uint8_t)(sim->spr[x].row + HK(sim, 0x7DD0 + x));
|
|
if (sim->spr[x].row < 0x25u) {
|
|
sim->spr[x].enable = 0u;
|
|
HK(sim, 0x7DB8 + x) = 0u;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Level G "TELEPORTS" ($7DA0 prelude0, $7DF2 per-tick2): orbs (hw 2..7)
|
|
// drift; touching the cab teleports it. Faithful reduction: place and
|
|
// drift the orb sprites (the teleport hop is a rare event we leave to
|
|
// the collision system, which crashes on contact like the C64's
|
|
// undelivered case -- see MECHANICS). Placement only for now.
|
|
static void hookGPerTick(StSimT *sim) {
|
|
// The orb colour cycles through $7DD4[phase] every 4 ticks.
|
|
HK(sim, 0x7E00)++;
|
|
if ((HK(sim, 0x7E00) & 3u) != 0u) {
|
|
return;
|
|
}
|
|
HK(sim, 0x7DD2)++;
|
|
if (HK(sim, 0x7DD2) == 6u) {
|
|
HK(sim, 0x7DD2) = 0u;
|
|
}
|
|
{
|
|
uint8_t c = HK(sim, 0x7DD4 + HK(sim, 0x7DD2));
|
|
uint8_t k;
|
|
for (k = 2u; k < ST_HW_SPRITES; k++) {
|
|
sim->spr[k].color = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Level U "REBOUND" ($7DAD per-tick2): the ceiling and side walls
|
|
// reflect the cab's velocity; hazard sprites (hw 3..7) drift. The wall
|
|
// bounce is the gimmick and is handled here on the taxi velocity.
|
|
static void hookUPerTick(StSimT *sim) {
|
|
if (sim->collisionPhase != 0u) {
|
|
return;
|
|
}
|
|
// $7DB2: near the top -> reflect Y downward.
|
|
if (sim->spr[0].row < 0x11u) {
|
|
sim->velY = (int16_t)(-sim->velY);
|
|
sim->spr[0].row = (uint8_t)(sim->spr[0].row + 2u);
|
|
}
|
|
}
|
|
|
|
|
|
#endif /* !IIGS */
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Dispatch
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// $7D75 -- 0 means sprite contact (passenger, level sprites) is safe.
|
|
uint8_t stHookHitVerdict(StSimT *sim) {
|
|
switch (sim->hookLevel) {
|
|
case ST_LEVEL_H:
|
|
return 0u;
|
|
default:
|
|
return 1u;
|
|
}
|
|
}
|
|
|
|
|
|
// $7D72 -- the input filter.
|
|
uint8_t stHookInput(StSimT *sim, uint8_t input) {
|
|
#if !defined(__W65816__)
|
|
switch (sim->hookLevel) {
|
|
case ST_LEVEL_Q:
|
|
return hookQInput(sim, input);
|
|
default:
|
|
break;
|
|
}
|
|
#else
|
|
(void)sim;
|
|
#endif
|
|
return input;
|
|
}
|
|
|
|
|
|
// $7D6C -- before the sprite flush.
|
|
void stHookPerTick2(StSimT *sim) {
|
|
switch (sim->hookLevel) {
|
|
case ST_LEVEL_H:
|
|
hookHPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_T:
|
|
hookTPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_W:
|
|
hookWPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_X:
|
|
hookXPerTick(sim);
|
|
break;
|
|
#if !defined(__W65816__)
|
|
case ST_LEVEL_V:
|
|
hookVPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_Q:
|
|
hookQPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_I:
|
|
hookIPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_G:
|
|
hookGPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_U:
|
|
hookUPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_K:
|
|
hookKPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_O:
|
|
hookOPerTick(sim);
|
|
break;
|
|
case ST_LEVEL_R:
|
|
hookRPerTick(sim);
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// $7D6F -- after the sprite flush.
|
|
void stHookPerTick3(StSimT *sim) {
|
|
(void)sim;
|
|
}
|
|
|
|
|
|
// $7D66 -- first prelude hook.
|
|
void stHookPrelude0(StSimT *sim) {
|
|
switch (sim->hookLevel) {
|
|
case ST_LEVEL_H:
|
|
hookHPrelude0(sim);
|
|
break;
|
|
case ST_LEVEL_X:
|
|
hookXPrelude0(sim);
|
|
break;
|
|
#if !defined(__W65816__)
|
|
case ST_LEVEL_Q:
|
|
hookQPrelude(sim);
|
|
break;
|
|
case ST_LEVEL_I:
|
|
hookIPrelude(sim);
|
|
break;
|
|
#endif
|
|
case ST_LEVEL_W:
|
|
{
|
|
uint8_t k;
|
|
for (k = 1u; k <= 8u; k++) {
|
|
HK(sim, 0x7DAB + k) = 0u;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// $7D69 -- second prelude hook.
|
|
void stHookPrelude1(StSimT *sim) {
|
|
switch (sim->hookLevel) {
|
|
case ST_LEVEL_T:
|
|
hookTPrelude1(sim);
|
|
break;
|
|
case ST_LEVEL_W:
|
|
HK(sim, 0x7DE5) = 1u;
|
|
break;
|
|
#if !defined(__W65816__)
|
|
case ST_LEVEL_R:
|
|
hookRMaze(sim, ST_CHAR_BLANK);
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|