#include #include #include #include #include #include #include #include "levelpack.h" #include "level.h" #include "items.h" #include "main.h" #define bool_t uint8_t struct levelpack { uint16_t signature; uint8_t version; uint8_t status; uint8_t levels_count; uint8_t player_lives; }; static ti_var_t appvar; static struct levelpack levelpack; static bool_t levelpack_read_bytes(void* dest, uint24_t size) { return (ti_Read(dest, size, 1, appvar) == 1); } static uint8_t levelpack_read_byte(void) { char byte; if (!levelpack_read_bytes(&byte, 1)) byte = 0; return byte; } static uint8_t levelpack_skip_str(void) { char byte; for (;;) { if (!levelpack_read_bytes(&byte, 1)) return 0; if (!byte) return 1; } } bool_t levelpack_load_level_data_byte(uint8_t** ptr, uint8_t byte) { if (byte == ITEM_MAGIC_WALL) { byte = (ITEM_WALL | HIDDEN_MAGIC_WALL); } else if (byte == ITEM_EXIT) { byte = (ITEM_STEEL_WALL | HIDDEN_EXIT); } else if (byte >= ITEM_COUNT) { return false; } *(*ptr)++ = byte; return true; } bool_t levelpack_load_level_data(void) { uint8_t* ptr = &level_data[0]; uint8_t byte; level.size = level.sizeX * level.sizeY; /* if (level.size <= LEVEL_SIZE_MAX) { */ switch(levelpack_read_byte()) { /* compression */ case 0: /* none */ level.size = (level.size + 1) / 2; for (;;) { byte = levelpack_read_byte(); if (!levelpack_load_level_data_byte(&ptr, (byte >> ITEM_BITS))) return false; if (!levelpack_load_level_data_byte(&ptr, (byte & ITEM_MASK))) return false; if (!--level.size) goto done; } break; case 1: /* RLE */ for (;;) { uint8_t reps; byte = levelpack_read_byte(); reps = (byte >> ITEM_BITS) + 1; byte = (byte & ITEM_MASK); while (reps --> 0) { if (!levelpack_load_level_data_byte(&ptr, byte)) return false; if (!--level.size) goto done; } } break; default: /* unknown */ return false; } /* } */ done: return true; } enum level_play_result levelpack_load_level(void) { if ( (levelpack_read_bytes(&level, sizeof(level))) && (levelpack_read_bytes(&entities[0], sizeof(entities[0]) * level.entities_count)) && (levelpack_load_level_data()) ) { // the coordinates of the initial view of the level are stored in the levelpack // they are computed for the TI-83 Plus version of the game, which uses 8x8 sprites on a 96x64 pixels screen // these coordinates have to be adjusted for the TI CE, to keep the view's center on the center of the screen level.viewX -= (SCREEN_SPRITES_X - (96/8)) / 2; level.viewY -= (SCREEN_SPRITES_Y - (64/8)) / 2; // the view may overflow a boundary of the level, if it was close to one // (this couldn't happen on the TI-83 Plus, but it can on the TI CE because the view is bigger) // if the level is bigger than the view, moves the view so that it fits in the level boundaries // if the view is bigger than the level, shows the level at the center of the view if (level.sizeX <= SCREEN_SPRITES_X) level.viewX = - ((SCREEN_SPRITES_X - level.sizeX) / 2); else if (((uint8_t)(level.viewX)) > 256 - SCREEN_SPRITES_X) level.viewX = 0; else if (((uint8_t)(level.viewX + SCREEN_SPRITES_X)) > level.sizeX) level.viewX = (level.sizeX - SCREEN_SPRITES_X); if (level.sizeY <= SCREEN_SPRITES_Y) level.viewY = - ((SCREEN_SPRITES_Y - level.sizeY) / 2); else if (((uint8_t)(level.viewY)) > 256 - SCREEN_SPRITES_Y) level.viewY = 0; else if (((uint8_t)(level.viewY + SCREEN_SPRITES_Y)) > level.sizeY) level.viewY = (level.sizeY - SCREEN_SPRITES_Y); /* play */ return level_play(); } else { /* quit */ return QUIT; } } void levelpack_load(const char* name) { if ( (appvar = ti_Open(name, "r")) && (levelpack_read_bytes(&levelpack, sizeof(levelpack))) && (!(levelpack.status & 0xFE)) && (levelpack_skip_str()) ) { progress.player_lives = levelpack.player_lives; progress.level_index = 1; while (levelpack.levels_count --> 0) { uint16_t level_position = ti_Tell(appvar); enum level_play_result result; replay: result = levelpack_load_level(); if (result == QUIT) break; if (result == DIED) { if (progress.player_lives) { if (!--progress.player_lives) { break; } } ti_Seek(level_position, SEEK_SET, appvar); goto replay; } ++progress.level_index; } } ti_CloseAll(); }