kobodl/map.cpp
Ville Lindholm dbc223eb84
Initial commit
Import existing source tree; original VCS history is no longer available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 16:35:31 +03:00

221 lines
4.9 KiB
C++

/*(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;
}