#include "asset.h" #include "random.h" #include "map.h" #include "rect.h" #include "render.h" #include "world.h" #define null_tile 0xffff Rect tile_rects[] = { #define x(n, x, y) \ { x, y, map_tile_size, map_tile_size }, tiles_xmacro #undef x }; void generate_room(Map* m, int r) { const Bitmap* b = get_bitmap(asset_id_rooms_img); const unsigned* p = (const unsigned*)&b[1]; #ifdef force_room r = force_room; #endif int o = r * map_w * map_h; int e = map_w * map_h, i; for (i = 0; i < e; i++, o++) { int bit = 1 << (o & 0x1f); if (p[o >> 5] & bit) { if ((get_r() & 127) == 0) m->tiles[i] = tile_block1; else if ((get_r() & 127) == 0) m->tiles[i] = tile_stone; else m->tiles[i] = tile_brick; } else m->tiles[i] = null_tile; } } unsigned short get_collider(Map_Tile t) { switch (t) { case tile_stone: case tile_block1: case tile_block2: case tile_window_top: case tile_window_mid: case tile_window_bot: case tile_brick_floor: case tile_trapdoor1: case tile_trapdoor2: case tile_brick: return 1; case tile_brick_ramp5: case tile_stone_ramp5: return 2; case tile_brick_ramp6: case tile_stone_ramp6: return 3; case tile_brick_ramp7: case tile_stone_ramp7: return 4; case tile_brick_ramp8: case tile_stone_ramp8: return 5; default: return 0; } } void generate_collision(Map* m) { int e = map_w * map_h, i; for (i = 0; i < e; i++) m->collision[i] = get_collider(m->tiles[i]); } int imp_check(Map* m, Map_Tile t, int x, int y) { return x >= 0 && y >= 0 && x < map_w && y < map_h && m->tiles[x + y * map_w] == t; } #define check(ox, oy, t) \ imp_check(m, t, x + ox, y + oy) #define place(t) \ m->tiles[x + y * map_w] = t #define place_o(t, ox, oy) \ m->tiles[x + ox + (y + oy) * map_w] = t #define place_a(t, x, y) \ m->tiles[x + y * map_w] = t void generate_ramps(Map* m) { int x, y; for (y = 0; y < map_h; y++) for (x = 0; x < map_w; x++) { if ( check( 0, 0, null_tile) && check( 1, 0, null_tile) && check(-1, 0, tile_brick) && !check(-1, -1, tile_brick) && check( 0, 1, tile_brick) && check( 1, 1, tile_brick) ) { place(tile_brick_ramp7); place_o(tile_brick_ramp8, 1, 0); } if ( check( 0, 0, null_tile) && check(-1, 0, null_tile) && check( 1, 0, tile_brick) && !check( 1, -1, tile_brick) && check( 0, 1, tile_brick) && check(-1, 1, tile_brick) ) { place(tile_brick_ramp6); place_o(tile_brick_ramp5, -1, 0); } if ( check(0, 0, tile_brick) && check(0, 1, tile_brick) && check(0, 2, tile_brick) && (( check(1, 0, null_tile) && check(1, 1, null_tile) && check(1, 2, null_tile)) || ( check(-1, 0, null_tile) && check(-1, 1, null_tile) && check(-1, 2, null_tile))) ) { place(tile_window_top); place_o(tile_window_mid, 0, 1); place_o(tile_window_bot, 0, 2); } } } void generate_floors(Map* m) { int x, y; for (y = 0; y < map_h; y++) for (x = 0; x < map_w; x++) { if ( check(0, 0, tile_brick) && check(0, -1, null_tile) ) place(tile_brick_floor); } } void generate_doors(Map* m) { const int hx = map_w >> 1; const int t = 0; const int b = map_h - 1; place_a(tile_trapdoor1, hx, b); place_a(tile_trapdoor2, hx + 1, b); place_a(tile_trapdoor3, hx, t); place_a(tile_trapdoor4, hx + 1, t); } #undef check #undef place #undef place_a #undef place_o void generate_enemies(const Map* m, World* w) { #define check \ (m->collision[x + y * map_w] == 1 && \ m->collision[x + (y - 1) * map_w] == 0) int x, y, ex = map_w - 1, ey = map_h - 1; /* enemies on platforms */ for (y = 1; y < ey; y++) { for (x = 1; x < ex; x++) { int plat = -1; for (; x < ex; x++) if (check) { plat = 0; break; } if (!plat) for (; check && x < ex; x++, plat++); if (plat >= 3) { Enemy* e; int sx = x - (plat >> 1); e = inst_enemy( w, enemy_demon, (sx * map_tile_size) << fbits, ((y - 1) * map_tile_size) << fbits ); e->face = get_r() & 1; } for (; check && x < ex; x++); } } /* flying enemies */ for (y = 1; y < ey; y++) { int next_y = y; for (x = 1; x < ex; x++) { int i = 0, j = 0; int ei = x + 4, ej = y + 4; int ok = 1; for (j = y; j < ej; j++) for (i = x; i < ei; i++) { if (m->collision[i + j * map_w]) ok = 0; } if (ok) { Enemy* e; e = inst_enemy( w, enemy_fly, ((x + 2) * map_tile_size) << fbits, ((y + 2) * map_tile_size) << fbits ); e->face = get_r() & 1; x = i; next_y = j; } } y = next_y; } } void generate_floor(Map* m, World* w, int fi) { Player* p = &w->player; w->enemy_count = 0; w->effect_count = 0; w->deathzone_count = 0; set_ri(0); generate_room(m, fi); generate_ramps(m); generate_doors(m); generate_floors(m); generate_collision(m); generate_enemies(m, w); p->x = (map_w >> 1) << fbits; p->y = (map_h - 2) << fbits; p->x *= map_tile_size; p->y *= map_tile_size; p->x += (map_tile_size >> 1) << fbits; p->vx = 0; p->vy = 0; } void render_map(const Map* m, Renderer* r) { const Bitmap* tm = get_bitmap(asset_id_map_img); int t = 0, x, y; for (y = 0; y < map_h; y++) { for (x = 0; x < map_w; x++, t++) { int tile = m->tiles[t]; if (tile != null_tile) ren_map( r, x * map_tile_size, y * map_tile_size, &tile_rects[tile], tm ); } } } #define place(t, c, x, y) { \ m->tiles[x + y * map_w] = t; \ m->collision[x + y * map_w] = c; \ } #define ncol(x, y) \ m->collision[x + y * map_w] = 0; void generate_intro(Map* m, struct World* w) { int i, j, b = map_h - 1; int e = map_w * map_h; for (i = 0; i < e; i++) { m->tiles[i] = null_tile; m->collision[i] = 0; } for (i = 0; i < map_w; i++) { int bot = b * map_w; m->collision[i] = 1; m->tiles[i + bot] = tile_stone; m->collision[i + bot] = 1; } b = map_w - 1; for (i = 0; i < map_h; i++) m->collision[b + i * map_w] = 1; for (i = 0; i < 15; i++) place(tile_stone, 1, i, 13); for (i = 0; i < 14; i++) place(tile_stone, 1, i, 12); for (i = 0; i < 12; i++) place(tile_stone, 1, i, 11); for (i = 0; i < 10; i++) place(tile_stone, 1, i, 10); place(tile_stone_ramp7, 4, 15, 13); place(tile_stone_ramp8, 5, 16, 13); place(tile_stone_ramp10, 7, 14, 12); place(tile_stone_ramp7, 4, 12, 11); place(tile_stone_ramp8, 5, 13, 11); place(tile_stone_ramp7, 4, 10, 10); place(tile_stone_ramp8, 5, 11, 10); for (j = 0; j < 10; j++) for (i = 0; i < 5; i++) place(tile_brick, 1, i, j); place(tile_trapdoor3, 0, 4, 9); place(tile_brick_dark, 0, 3, 9); place(tile_gate, 0, 2, 9); place(tile_window_top, 1, 4, 3); place(tile_window_mid, 1, 4, 4); place(tile_window_bot, 1, 4, 5); place(tile_window_top, 1, 4, 0); place(tile_window_mid, 1, 4, 1); place(tile_window_bot, 1, 4, 2); w->player.x = (18 * map_tile_size) << fbits; w->player.y = (13 * map_tile_size) << fbits; } void generate_outro(Map* m, struct World* w) { int i, j; int e = map_w * map_h; for (i = 0; i < e; i++) { m->tiles[i] = null_tile; m->collision[i] = 0; } for (j = 10; j < map_h; j++) for (i = 0; i < map_w; i++) place(tile_brick, 1, i, j); for (i = 0; i < map_w; i++) if (i & 1) place(tile_brick_floor, 0, i, 9); for (i = 0; i < map_h; i++) { int y = i * map_w; m->collision[y + (map_w - 1)] = 1; m->collision[y] = 1; } w->player.x = (map_w >> 1) << fbits; w->player.x *= map_tile_size; w->player.x += (map_tile_size >> 1) << fbits; w->player.y = (9 * map_tile_size) << fbits; } #undef place #undef ncol int room_count(void) { const Bitmap* bm = get_bitmap(asset_id_rooms_img); return bm->h / map_h; }