#include #include #include #include #include #include #include #include "levelpack.h" #include "progress.h" #include "menu.h" #include "level.h" #include "items.h" #include "main.h" #define LEVELPACKED_SIZE LEVEL_CELLS #define LEVELPACK_HEADER_SIZE 7 static const uint8_t levelpack_header_expected[LEVELPACK_HEADER_SIZE] = { 'R', 'G', 'B', 'E', 0xEE, 0x01, 0x00 }; static ti_var_t appvar; static uint8_t levelpack_header[LEVELPACK_HEADER_SIZE]; static uint8_t levelpacked[LEVELPACKED_SIZE]; void levelpack_load_levelpacked_roads(void) { //static const uint8_t dir_bit[4] = {1, 2, 4, 8}; static const int8_t dir_dx[4] = {0, 1, -1, 0}; static const int8_t dir_dy[4] = {1, 0, 0, -1}; #define dir_bit(dir) (0x10 << (dir)) #define dir_op(dir) (3 - (dir)) //uint8_t bit; for (bit = 0x10; bit; bit <<= 1) {// uint8_t dir; for (dir = 0; dir < 4; dir++) { //uint8_t bit_prev = 0x01 << dir;// //uint8_t bit = bit_prev << 4;// uint8_t y; for (y = 1; y <= 11; y++) { uint8_t x; for (x = 1; x <= 11; x++) { uint8_t index = (y*16)+x; if ((cells_ground_type[index] == GROUND_ROAD) && (cells_ground_links[index] & dir_bit(dir))) { uint8_t x_next = x + dir_dx[dir]; uint8_t y_next = y + dir_dy[dir]; uint8_t index_next = (y_next*16)+x_next; if ((!(cells_ground_type[index_next] == GROUND_ROAD)) || (!(cells_ground_links[index_next] & dir_bit(dir_op(dir))))) { cells_ground_links[index] ^= dir_bit(dir); } } } } } #undef dit_bit #undef dir_op } bool levelpack_load_levelpacked(void) { uint8_t* ptr = &levelpacked[0]; static uint8_t levelpacked_queue[LEVEL_CELLS]; uint8_t levelpacked_queue_producer = 0; uint8_t levelpacked_queue_consumer = 0; #define magic_goto_call(l) magic_goto_call_used = 1; goto l; magic_goto_return: magic_goto_call_used = 0; uint8_t magic_goto_call_used = 0; memset(&level.count, 0, sizeof(struct level_items_count)); { uint8_t y; for (y = 1; y <= 11; y++) { uint8_t x; for (x = 1; x <= 11; x++) { uint8_t index = y*16+x; uint8_t byte = *ptr++; uint8_t ground_type, ground_links, item_type, item_color, item_state; ground_type = GROUND_NONE; ground_links = 0; item_type = ITEM_NONE; item_color = 0; item_state = 0; switch (byte & /*11......*/0xC0) { case /*01......*/0x40: ground_type = GROUND_GRASS; if (byte & /*--111111*/0x3F) { if ((byte & /*--11....*/0x30) == /*--01....*/0x10) { item_type = ITEM_BRIDGE; item_state = ((byte & /*----11--*/0x0C) >> 2); item_color = (byte & /*------11*/0x03); ground_type = GROUND_ROAD; ground_links = (byte & /*----1---*/0x08) ? 0x90 : 0x60; } else { if (++levelpacked_queue_producer > levelpacked_queue_consumer) { levelpacked_queue[levelpacked_queue_producer-1] = byte & /*00111111*/0x3F; } else { magic_goto_call(levelpack_load_levelpacked_road_item); { uint8_t itempacked_index = levelpacked_queue[levelpacked_queue_producer-1]; cells_item_type[itempacked_index] = item_type; cells_item_color[itempacked_index] = item_color; cells_item_state[itempacked_index] = item_state; item_type = ITEM_NONE; item_color = 0; item_state = 0; } } } } break; case /*10......*/0x80: ground_type = GROUND_GRASS; if (byte & /*---1....*/0x10) { if (byte & /*----1-..*/0x08) { item_color = COLOR_PURPLE; goto levelpack_load_levelpacked_truck_dir; } else if (byte & /*----1..*/0x04) { goto levelpack_load_levelpacked_cargo; } else { item_type = ITEM_HOUSE; ++level.count.houses; goto levelpack_load_levelpacked_item_color; } } break; case /*11......*/0xC0: ground_type = GROUND_ROAD; ground_links = 0xF0; levelpack_load_levelpacked_road_item: if (byte & /*--1.....*/0x20) { item_color = ((byte & /*---111--*/0x1C) >> 2) + 1; levelpack_load_levelpacked_truck_dir: item_type = ITEM_TRUCK; item_state = (byte & /*------11*/0x03); ++level.count.trucks; if (item_color == COLOR_WHITE) ++level.count.whitetrucks; if (item_color == COLOR_PURPLE) ++level.count.hoverboards; } else if (byte & /*---1....*/0x10) { } else if (byte & /*----1...*/0x08) { item_type = ITEM_BUTTON; item_state = ((byte & /*-----1--*/0x04) >> 2); item_color = (byte & /*------11*/0x03); ++level.count.buttons; } else if (byte & /*-----1..*/0x04) { levelpack_load_levelpacked_cargo: item_type = ITEM_CARGO; ++level.count.cargos; levelpack_load_levelpacked_item_color: item_color = (byte & /*------11*/0x03) + 1; } else if (byte & /*------1.*/0x02) { } else if (byte & /*-------1*/0x01) { item_type = ITEM_DROPPOINT; ++level.count.droppoints; } if (magic_goto_call_used) goto magic_goto_return; break; default: if (byte & /*--1.....*/0x20) { ground_type = GROUND_ROAD; ground_links = 0xF0 & (~(byte << 4)); if (byte & /*---1....*/0x10) { if (++levelpacked_queue_consumer <= levelpacked_queue_producer) { byte = levelpacked_queue[levelpacked_queue_consumer-1]; goto levelpack_load_levelpacked_road_item; } else { levelpacked_queue[levelpacked_queue_consumer-1] = index; } } } else if (byte & /*--01....*/0x10) { ground_type = GROUND_WATER; //ground_links = 0xF0 & (~(byte << 4)); // UNUSED } break; } cells_ground_type[index] = ground_type; cells_ground_links[index] = ground_links; cells_item_type[index] = item_type; cells_item_color[index] = item_color; cells_item_state[index] = item_state; } } } if (levelpacked_queue_producer != levelpacked_queue_consumer) return false; levelpack_load_levelpacked_roads(); return true; } enum level_play_result levelpack_load_level(void) { uint16_t level_position = (level.level_index-1) * LEVELPACKED_SIZE + LEVELPACK_HEADER_SIZE; if ( (ti_Seek(level_position, SEEK_SET, appvar) != EOF) && (ti_Read(&levelpacked, sizeof(levelpacked), 1, appvar) == 1) // && (levelpack_load_levelpacked()) ) { /* play */ return levelpack_load_levelpacked() ? level_play() : DONE; // return level_play(); } else { /* quit */ return QUIT; } } void levelpack_play(void) { menu_levels_count = ( (appvar = ti_Open("RGBELVLS", "r")) && (ti_Read(&levelpack_header[0], LEVELPACK_HEADER_SIZE, 1, appvar) == 1) && (memcmp(levelpack_header, levelpack_header_expected, LEVELPACK_HEADER_SIZE) == 0) ) ? (ti_GetSize(appvar) - LEVELPACK_HEADER_SIZE) / LEVELPACKED_SIZE : 0; menu(); ti_CloseAll(); }