/*
* This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
*
* Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
* Copyright (©) 1994,2007 Mark Wedel
* Copyright (©) 1992,2007 Frank Tore Johansen
*
* Crossfire TRT 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 3 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, see .
*
* The authors can be reached via e-mail to
*/
/* The onion room generator:
Onion rooms are like this:
char **map_gen_spiral(int xsize, int ysize, int option);
*/
#include
#include
#define RANDOM_OPTIONS 0 /* Pick random options below */
#define REGULAR_SPIRAL 1 /* Regular spiral--distance increases constantly */
#define FINE_SPIRAL 2 /* uses the min. separation: most coiling */
#define FIT_SPIRAL 4 /* scale to a rectangular region, not square */
#define MAX_SPIRAL_OPT 8 /* this should be 2x the last real option */
#include
#ifndef MIN
# define MIN(x,y) (((x)<(y))? (x):(y))
#endif
#ifndef MAX
# define MAX(x,y) (((x)<(y))? (y):(x))
#endif
#define MINDIST 3
#define MAX_FINE .454545
extern int surround_check (char **maze, int i, int j, int xsize, int ysize);
char **
map_gen_spiral (int xsize, int ysize, int option)
{
int i, j;
float parm = 0;
float x = 0, y = 0;
int ic, jc;
float SizeX, SizeY;
float xscale, yscale;
/* allocate that array, set it up */
char **maze = (char **) calloc (sizeof (char *), xsize);
for (i = 0; i < xsize; i++)
{
maze[i] = (char *) calloc (sizeof (char), ysize);
}
/* slightly easier to fill and then cut */
for (i = 0; i < xsize; i++)
for (j = 0; j < ysize; j++)
maze[i][j] = '#';
ic = xsize / 2;
jc = ysize / 2;
SizeX = xsize / 2 - 2;
SizeY = ysize / 2 - 2;
/* select random options if necessary */
if (option == 0)
{
option = rndm (MAX_SPIRAL_OPT);
}
/* the order in which these are evaluated matters */
/* the following two are mutually exclusive.
pick one if they're both set. */
if ((option & REGULAR_SPIRAL) && (option & FIT_SPIRAL))
{
/* unset REGULAR_SPIRAL half the time */
if (rndm (2) && (option & REGULAR_SPIRAL))
option -= REGULAR_SPIRAL;
else
option -= FIT_SPIRAL;
}
xscale = yscale = MAX_FINE; /* fine spiral */
/* choose the spiral pitch */
if (!(option & FINE_SPIRAL))
{
float pitch = (rndm (5)) / 10. + 10. / 22.;
xscale = yscale = pitch;
}
if ((option & FIT_SPIRAL) && (xsize != ysize))
{
if (xsize > ysize)
xscale *= (float) xsize / (float) ysize;
else
yscale *= (float) ysize / (float) xsize;
}
if (option & REGULAR_SPIRAL)
{
float scale = MIN (xscale, yscale);
xscale = yscale = scale;
}
/* cut out the spiral */
while ((fabs (x) < SizeX) && (fabs (y) < SizeY))
{
x = parm * cos (parm) * xscale;
y = parm * sin (parm) * yscale;
maze[(int) (ic + x)][(int) (jc + y)] = '\0';
parm += 0.01;
};
maze[(int) (ic + x + 0.5)][(int) (jc + y + 0.5)] = '<';
/* cut out the center in a 2x2 and place the center and downexit */
maze[ic][jc + 1] = '>';
maze[ic][jc] = 'C';
return maze;
}
/* the following function connects disjoint spirals which may
result from the symmetrization process. */
void
connect_spirals (int xsize, int ysize, int sym, char **layout)
{
int i, j, ic = xsize / 2, jc = ysize / 2;
if (sym == SYMMETRY_X)
{
layout[ic][jc] = 0;
/* go left from map center */
for (i = ic - 1, j = jc; i > 0 && layout[i][j] == '#'; i--)
layout[i][j] = 0;
/* go right */
for (i = ic + 1, j = jc; i < xsize - 1 && layout[i][j] == '#'; i++)
layout[i][j] = 0;
}
if (sym == SYMMETRY_Y)
{
layout[ic][jc] = 0;
/* go up */
for (i = ic, j = jc - 1; j > 0 && layout[i][j] == '#'; j--)
layout[i][j] = 0;
/* go down */
for (i = ic, j = jc + 1; j < ysize - 1 && layout[i][j] == '#'; j++)
layout[i][j] = 0;
}
if (sym == SYMMETRY_XY)
{
/* go left from map center */
layout[ic][jc / 2] = 0;
layout[ic / 2][jc] = 0;
layout[ic][jc / 2 + jc] = 0;
layout[ic / 2 + ic][jc] = 0;
for (i = ic - 1, j = jc / 2; i > 0 && layout[i][j] == '#'; i--)
{
layout[i][j + jc] = 0;
layout[i][j] = 0;
}
/* go right */
for (i = ic + 1, j = jc / 2; i < xsize - 1 && layout[i][j] == '#'; i++)
{
layout[i][j + jc] = 0;
layout[i][j] = 0;
}
/* go up */
for (i = ic / 2, j = jc - 1; j > 0 && layout[i][j] == '#'; j--)
{
layout[i][j] = 0;
layout[i + ic][j] = 0;
}
/* go down */
for (i = ic / 2, j = jc + 1; j < ysize - 1 && layout[i][j] == '#'; j++)
{
layout[i][j] = 0;
layout[i + ic][j] = 0;
}
}
/* get rid of bad doors. */
for (i = 0; i < xsize; i++)
for (j = 0; j < ysize; j++)
{
if (layout[i][j] == 'D')
{ /* remove bad door. */
int si = surround_check (layout, i, j, xsize, ysize);
if (si != 3 && si != 12)
{
layout[i][j] = 0;
/* back up and recheck any nearby doors */
i = 0;
j = 0;
}
}
}
}