#include #include #include #include #include #include "level.h" #include "level_test.h" #include "items.h" #include "paths.h" #include "main.h" #include "draw.h" uint8_t backup_paths_links[256]; uint8_t backup_item_type[256]; uint8_t backup_item_color[256]; uint8_t backup_item_state[256]; static bool cells_smoke[256]; static uint8_t level_houses_done; extern struct level level; #define TEST_FLAGS_CELL backup_item_type #define TEST_FLAGS_MASK 0x7F #define TEST_FLAG_MOVED 0x80 static uint8_t level_test_init(void) { level_trucks_init(); { uint8_t level_trucks_used = level_trucks_dir(); uint8_t position; for (position = 0; ++position; ) { if (cells_item_type[position] == ITEM_DROPPOINT) { if (!cells_item_state[position]) cells_item_type[position] = ITEM_NONE; else cells_item_state[position] = 2; } } level_houses_done = 0; return level_trucks_used; } } static bool level_test_toggle_color(uint8_t color) { bool dead = false; uint8_t position; for (position = 0; ++position; ) { if (cells_item_color[position] == color) { if (cells_item_type[position] == ITEM_BUTTON) { cell_toggle_state: cells_item_state[position] ^= 1; } else if (cells_item_type[position] == ITEM_BRIDGE) { if (TEST_FLAGS_CELL[position] & TEST_FLAG_MOVED) { cells_smoke[position] = dead = true; } goto cell_toggle_state; } } } return dead; } static enum level_play_result level_test_step(void) { static const uint8_t bridge_cross_check[] = {1,0,0,1}; bool dead = false; bool done = true; struct truck* truck; uint8_t index; for (truck = &level_trucks[0], index = 0; index < level.count.trucks; ++truck, ++index) { uint8_t position = truck->position; uint8_t direction = truck->directions_last_next & 0x0F; if (direction != DIR_0) { truck->directions_last_next = (direction << 4) | (paths_direction_step(&paths_connections[position], direction)); switch (direction) { case DIR_U: position-=16; break; case DIR_L: --position; break; case DIR_R: ++position; break; case DIR_D: position+=16; break; } truck->position = position; done = false; } } for (truck = &level_trucks[0], index = 0; index < level.count.trucks; ++truck, ++index) { const uint8_t position = truck->position; const uint8_t above = position - 16; if (cells_item_type[above] == ITEM_HOUSE && !cells_item_state[above]) { if ((cells_item_color[above] == truck->color || truck->color >= COLOR_WHITE) && (truck->cargos[0] == cells_item_color[above])) { truck->cargos[0] = truck->cargos[1]; truck->cargos[1] = truck->cargos[2]; truck->cargos[2] = COLOR_NONE; cells_item_state[above] = 1; ++level_houses_done; } else { cells_smoke[above] = dead = true; } } if (cells_item_type[position] == ITEM_CARGO && truck->cargos[2] == COLOR_NONE) { truck->cargos[2] = truck->cargos[1]; truck->cargos[1] = truck->cargos[0]; truck->cargos[0] = cells_item_color[position]; cells_item_type[position] = ITEM_NONE; //cells_item_color[position] = COLOR_NONE; } else if (cells_item_type[position] == ITEM_DROPPOINT) { cells_item_type[position] = ITEM_NONE; if (truck->cargos[0] != COLOR_NONE) { cells_item_type[position] = ITEM_CARGO; cells_item_color[position] = truck->cargos[0]; truck->cargos[0] = truck->cargos[1]; truck->cargos[1] = truck->cargos[2]; truck->cargos[2] = COLOR_NONE; } } if (TEST_FLAGS_CELL[position] & TEST_FLAG_MOVED) { cells_smoke[position] = dead = true; } TEST_FLAGS_CELL[position] |= TEST_FLAG_MOVED; } for (truck = &level_trucks[0], index = 0; index < level.count.trucks; ++truck, ++index) { const uint8_t position = truck->position; if (cells_item_type[position] == ITEM_BUTTON && !cells_item_state[position]) { dead |= level_test_toggle_color(cells_item_color[position]); } else if (cells_item_type[position] == ITEM_BRIDGE) { if ((cells_item_state[position] & 1) != (bridge_cross_check[(truck->directions_last_next >> 4) - 1] == (cells_item_state[position] >> 1))) { cells_smoke[position] = dead = true; } } } for (truck = &level_trucks[0], index = 0; index < level.count.trucks; ++truck, ++index) { TEST_FLAGS_CELL[truck->position] &= TEST_FLAGS_MASK; } level_draw(); if (dead) { uint8_t y; for (y = 1; y <= 11; ++y) { uint8_t x; for (x = 1; x <= 11; ++x) { if (cells_smoke[index = y*16+x]) { draw_smoke(x, y); } } } } draw_done(); if (global_delay < 65) { delay(65 - global_delay); } global_delay = 0; return (dead ? DIED : (done ? (level_houses_done == level.count.houses ? DONE : QUIT) : PLAYING)); } enum level_play_result level_test_loop(void) { enum level_play_result result/* = PLAYING*/; memcpy(backup_paths_links, paths_connections, 256); memcpy(backup_item_type , cells_item_type , 256); memcpy(backup_item_color , cells_item_color , 256); memcpy(backup_item_state , cells_item_state , 256); if (!level_test_init()) return PLAYING; memset(cells_smoke, false, sizeof(cells_smoke)); while ((result = level_test_step()) == PLAYING); memcpy(paths_connections, backup_paths_links, 256); memcpy(cells_item_type , backup_item_type , 256); memcpy(cells_item_color , backup_item_color , 256); memcpy(cells_item_state , backup_item_state , 256); level_trucks_init(); return (keys_wait() == kb_Enter) && (result == DONE) ? DONE : PLAYING; }