/*(GPL) ------------------------------------------------------------ Kobo Deluxe - An enhanced SDL port of XKobo ------------------------------------------------------------ * Copyright (C) 1995, 1996 Akira Higuchi * Copyright (C) 2002, 2007 David Olofson * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include "map.h" #include "random.h" void _map::init() { int i, j; for(i = 0; i < MAP_SIZEX; i++) for(j = 0; j < MAP_SIZEY; j++) pos(i, j) = SPACE; } void _map::make_maze(int x, int y, int difx, int dify) { int i, j; int vx, vy; /* clear */ for(i = x - difx; i <= x + difx; i++) for(j = y - dify; j <= y + dify; j++) pos(i, j) = SPACE; /* push initial sites */ site_max = 0; if(gamerand.get(8) < 128) { pos(x, y) = CORE | R_MASK | L_MASK; maze_push(x - 1, y); maze_push(x + 1, y); } else { pos(x, y) = CORE | U_MASK | D_MASK; maze_push(x, y - 1); maze_push(x, y + 1); } for(;;) { /* get one */ if(maze_pop()) break; vx = sitex[site_max]; vy = sitey[site_max]; int dirs[4]; for(i = 0; i < 4; i++) dirs[i] = 0; int dirs_max = 0; if(maze_judge(x, y, difx, dify, vx + 2, vy + 0)) dirs[dirs_max++] = 1; if(maze_judge(x, y, difx, dify, vx + 0, vy + 2)) dirs[dirs_max++] = 2; if(maze_judge(x, y, difx, dify, vx - 2, vy + 0)) dirs[dirs_max++] = 3; if(maze_judge(x, y, difx, dify, vx + 0, vy - 2)) dirs[dirs_max++] = 4; if(dirs_max == 0) continue; /* there are no places to go */ i = gamerand.get() % dirs_max; maze_move_and_push(vx, vy, dirs[i]); maze_push(vx, vy); } } int _map::maze_pop() { if(site_max == 0) return 1; int i = gamerand.get() % site_max; site_max--; if(i != site_max) { int tmpx = sitex[site_max]; int tmpy = sitey[site_max]; sitex[site_max] = sitex[i]; sitey[site_max] = sitey[i]; sitex[i] = tmpx; sitey[i] = tmpy; } return 0; } void _map::maze_push(int x, int y) { sitex[site_max] = x; sitey[site_max++] = y; pos(x, y) = WALL; } void _map::maze_move_and_push(int x, int y, int d) { int x1 = x; int y1 = y; switch (d) { case 1: { x1 += 2; break; } case 2: { y1 += 2; break; } case 3: { x1 -= 2; break; } case 4: { y1 -= 2; break; } } maze_push(x1, y1); pos((x + x1) / 2, (y + y1) / 2) = WALL; } int _map::maze_judge(int cx, int cy, int dx, int dy, int x, int y) { if((x < cx - dx) || (x > cx + dx) || (y < cy - dy) || (y > cy + dy)) return 0; if(pos(x, y) == WALL) return 0; return 1; } // Translate map "tile state bits" into tile index // // The hard end nodes need some special treatment here. There are 16 direction // mask combinations, but only 4 are valid in this case. So, we use a 16 x 2 // bit lookup "table" (packed into an 'int') to get the right tile index. // // 00 01 10 11 <-- mask bits 1 (right) and 0 (up) // ----------------------------------------------------- // 00 -- 00 01 -- // 01 10 -- -- -- <-- Tile indices // 10 11 -- -- -- // 11 -- -- -- -- // ^ // '- mask bits 3 (left) and 2 (down) // // Thus, our table is 00000000 00000011 00000010 00010000 == 0x00030210 // static inline int bits2tile(int n) { if(n & CORE) // Core return n & (U_MASK | D_MASK) ? 6 : 7; else if(n & HARD) // One of the 4 indestructible end nodes return (0x00030210 >> ((n & 15) << 1)) & 3; else if(n == 5) // Vertical pipe return pubrand.get(2) ? 13 : 4; else if(n == 10) // Vertical pipe return pubrand.get(2) ? 18 : 5; else // Other pipe parts or normal end nodes return n + 8; } void _map::convert(unsigned ratio) { int i, j; int p = 0; for(i = 0; i < MAP_SIZEX; i++) for(j = 0; j < MAP_SIZEY; j++) { p = pos(i, j) & CORE; if(IS_SPACE(pos(i, j))) { clearpos(i, j); continue; } if((j > 0) && !IS_SPACE(pos(i, j - 1))) p |= U_MASK; if((i < MAP_SIZEX - 1) && !IS_SPACE(pos(i + 1, j))) p |= R_MASK; if((j < MAP_SIZEY - 1) && !IS_SPACE(pos(i, j + 1))) p |= D_MASK; if((i > 0) && !IS_SPACE(pos(i - 1, j))) p |= L_MASK; if((p == U_MASK) || (p == R_MASK) || (p == D_MASK) || (p == L_MASK)) { if(gamerand.get(8) < ratio) p |= HARD; } pos(i, j) = (bits2tile(p) << 8) | p; } } void _map::clearpos(int x, int y) { pos(x, y) = (gamerand.get(6) << 8) | SPACE; }