// stsim -- host-side driver for the Space Taxi simulation core. // // Loads an STL4 level, attaches a recorded demo input stream and runs // the game tick, printing one line of state per tick in the same shape // the VICE tracer records (see stuff/spacetaxi and the compare script), // so the port's engine can be diffed against the real machine. // // stsim #include #include #include #include "../../examples/spacetaxi/stSim.h" #include "../../examples/spacetaxi/stDemoStreams.h" static StLevelT gLevel; static StSimT gSim; void stAudioSfx(const uint8_t *program9) { (void)program9; } void stAudioNoise(bool on) { (void)on; } void stAudioThrustSweep(uint8_t value) { (void)value; } void stAudioSpeech(uint8_t ch) { (void)ch; } void stAudioSilence(void) { } void stAudioVoice2(uint8_t freqLo, uint8_t freqHi, uint8_t ctrl) { (void)freqLo; (void)freqHi; (void)ctrl; } void stAudioVoice1Freq(uint8_t value) { (void)value; } static void printState(const StSimT *sim, uint32_t tick) { uint8_t k; printf("{\"tick\":%u,\"x\":\"%02X%02X.%02X\",\"y\":\"%02X.%02X\",\"vx\":\"%04X\",\"vy\":\"%04X\"," "\"pad\":%u,\"st\":%u,\"ph\":%u,\"in\":\"%02X\",\"dir\":\"%02X\",\"ptr0\":\"%02X\",\"ptr1\":\"%02X\"," "\"s1\":\"%02X%02X.%02X\",\"en\":\"%02X\",\"t4740\":\"%02X\",\"off\":%u,\"rng\":\"%02X%02X\"," "\"fuel\":%u,\"slots\":%u,\"asi\":%u,\"score\":\"", tick, sim->posXmsb, sim->posXcol, sim->posXlo, sim->posYrow, sim->posYlo, (uint16_t)sim->velX, (uint16_t)sim->velY, sim->activePad, sim->stage, sim->collisionPhase, sim->inputMask, sim->dirMask, sim->spr[0].ptr, sim->spr[1].ptr, sim->spr[1].msb, sim->spr[1].col, sim->spr[1].row, sim->frame.enableMask, sim->demoTimer, sim->demoOff, sim->rngT1, sim->rngT2, sim->fuelCells, sim->fareSlotCount, sim->activeSpriteIdx); for (k = 0u; k < ST_NUMBER_CHARS; k++) { printf("%02X", sim->screen[ST_CELL_SCORE + k]); } printf("\",\"fare\":\""); for (k = 0u; k < ST_NUMBER_CHARS; k++) { printf("%02X", sim->screen[ST_CELL_FARE + k]); } printf("\",\"fuelc\":\""); for (k = 0u; k < ST_FUEL_CELLS; k++) { printf("%02X", sim->screen[ST_CELL_FUEL + k]); } printf("\",\"sprx\":\""); for (k = 0u; k < ST_HW_SPRITES; k++) { printf("%03X%02X", sim->frame.x[k], sim->frame.y[k]); } printf("\"}\n"); } int main(int argc, char **argv) { FILE *fp; const uint8_t *stream = kDemoStreamH; uint16_t len = (uint16_t)sizeof(kDemoStreamH); uint32_t ticks; uint32_t t; if (argc < 4) { fprintf(stderr, "usage: stsim \n"); return 2; } fp = fopen(argv[1], "rb"); if (fp == NULL || !stLevelParse(&gLevel, fp)) { fprintf(stderr, "stsim: cannot load %s\n", argv[1]); return 1; } fclose(fp); switch (argv[2][0]) { case 'W': stream = kDemoStreamW; len = (uint16_t)sizeof(kDemoStreamW); break; case 'T': stream = kDemoStreamT; len = (uint16_t)sizeof(kDemoStreamT); break; case 'X': stream = kDemoStreamX; len = (uint16_t)sizeof(kDemoStreamX); break; default: break; } ticks = (uint32_t)strtoul(argv[3], NULL, 0); stSimNewGame(&gSim, 1u, true); stSimSeedDemoBuffer(&gSim, kDemoBufferInit, ST_DEMO_BUFFER_BYTES); if (argc > 4) { // carried-over state: flame parity, wave index, walk parity gSim.flameParity = (uint8_t)strtoul(argv[4], NULL, 16); } if (argc > 5) { gSim.waveIdx = (uint8_t)strtoul(argv[5], NULL, 16); } if (argc > 6) { gSim.walkParity = (uint8_t)strtoul(argv[6], NULL, 16); } stSimEnterLevel(&gSim, &gLevel); stSimSetDemoStream(&gSim, stream, len); for (t = 0u; t < ticks; t++) { StTickResultE r; printState(&gSim, t); r = stSimTick(&gSim); if (r != ST_TICK_CONTINUE) { printf("{\"tick\":%u,\"end\":%d}\n", t, (int)r); break; } } return 0; }