server-1.12/random_maps/wall.c

484 lines
12 KiB
C

/*
* static char *rcsid_wall_c =
* "$Id: wall.c 11578 2009-02-23 22:02:27Z lalo $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 2002 Mark Wedel & Crossfire Development Team
Copyright (C) 1992 Frank Tore Johansen
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.
The authors can be reached via e-mail at crossfire-devel@real-time.com
*/
/**
* @file
* Deals with wall management in random maps.
*/
#include <global.h>
#include <random_map.h>
#include <rproto.h>
/**
* Given a layout and a coordinate, tell me which squares up/down/right/left
* are occupied.
* @param layout
* @param i
* @param j
* spot to look.
* @param RP
* map parameters.
* @return
* combination of:
* - 1 = something on left.
* - 2 = something on right.
* - 4 = something on above.
* - 8 = something on below.
* @todo
* merge with surround_flag2() and friends, check if such a function doesn't exist in other files.
*/
int surround_flag(char **layout, int i, int j, RMParms *RP) {
int surround_index = 0;
if ((i > 0) && layout[i-1][j] != 0)
surround_index |= 1;
if ((i < RP->Xsize-1) && layout[i+1][j] != 0)
surround_index |= 2;
if ((j > 0) && layout[i][j-1] != 0)
surround_index |= 4;
if ((j < RP->Ysize-1) && layout[i][j+1] != 0)
surround_index |= 8;
return surround_index;
}
/**
* Given a layout and a coordinate, tell me which squares up/down/right/left
* are occupied by walls.
* @param layout
* @param i
* @param j
* spot to look.
* @param RP
* map parameters.
* @return
* combination of:
* - 1 = wall on left.
* - 2 = wall on right.
* - 4 = wall on above.
* - 8 = wall on below.
* @todo
* merge with surround_flag() and friends, check if such a function doesn't exist in other files.
*/
int surround_flag2(char **layout, int i, int j, RMParms *RP) {
int surround_index = 0;
if ((i > 0) && layout[i-1][j] == '#')
surround_index |= 1;
if ((i < RP->Xsize-1) && layout[i+1][j] == '#')
surround_index |= 2;
if ((j > 0) && layout[i][j-1] == '#')
surround_index |= 4;
if ((j < RP->Ysize-1) && layout[i][j+1] == '#')
surround_index |= 8;
return surround_index;
}
/**
* Check a map for blocked spots.
* Since this is part of the random map code, presumption
* is that this is not a tiled map.
* What is considered blocking and not is somewhat hard coded.
* @param map
* @param i
* @param j
* spot to look.
* @param RP
* map parameters.
* @return
* combination of:
* - 1 = blocked on left.
* - 2 = blocked on right.
* - 4 = blocked on above.
* - 8 = blocked on below.
*/
int surround_flag3(mapstruct *map, int i, int j, RMParms *RP) {
int surround_index = 0;
if ((i > 0) && (GET_MAP_MOVE_BLOCK(map, i-1, j)&~MOVE_BLOCK_DEFAULT))
surround_index |= 1;
if ((i < RP->Xsize-1) && (GET_MAP_MOVE_BLOCK(map, i+1, j)&~MOVE_BLOCK_DEFAULT))
surround_index |= 2;
if ((j > 0) && (GET_MAP_MOVE_BLOCK(map, i, j-1)&~MOVE_BLOCK_DEFAULT))
surround_index |= 4;
if ((j < RP->Ysize-1) && (GET_MAP_MOVE_BLOCK(map, i, j+1)&~MOVE_BLOCK_DEFAULT))
surround_index |= 8;
return surround_index;
}
/**
* Check a map for spots with walls.
* Since this is part of the random map code, presumption
* is that this is not a tiled map.
* What is considered blocking and not is somewhat hard coded.
* @param map
* @param i
* @param j
* spot to look.
* @param RP
* map parameters.
* @return
* combination of:
* - 1 = blocked on left.
* - 2 = blocked on right.
* - 4 = blocked on above.
* - 8 = blocked on below.
*/
int surround_flag4(mapstruct *map, int i, int j, RMParms *RP) {
int surround_index = 0;
if ((i > 0) && wall_blocked(map, i-1, j))
surround_index |= 1;
if ((i < RP->Xsize-1) && wall_blocked(map, i+1, j))
surround_index |= 2;
if ((j > 0) && wall_blocked(map, i, j-1))
surround_index |= 4;
if ((j < RP->Ysize-1) && wall_blocked(map, i, j+1))
surround_index |= 8;
return surround_index;
}
/**
* takes a map and a layout, and puts walls in the map (picked from
* w_style) at '#' marks.
* @param map
* map where walls will be put.
* @param layout
* layout containing walls and such.
* @param w_style
* wall style. Must not be NULL, can be "none".
* @param RP
* map parameters.
*/
void make_map_walls(mapstruct *map, char **layout, char *w_style, RMParms *RP) {
char styledirname[256];
char stylefilepath[256];
mapstruct *style_map = NULL;
object *the_wall;
/* get the style map */
if (!strcmp(w_style, "none"))
return;
snprintf(styledirname, sizeof(styledirname), "%s", "/styles/wallstyles");
snprintf(stylefilepath, sizeof(stylefilepath), "%s/%s", styledirname, w_style);
style_map = find_style(styledirname, w_style, -1);
if (style_map == NULL)
return;
/* fill up the map with the given floor style */
if ((the_wall = pick_random_object(style_map)) != NULL) {
int i, j;
char *cp;
int joinedwalls = 0;
object *thiswall;
snprintf(RP->wall_name, sizeof(RP->wall_name), "%s", the_wall->arch->name);
if ((cp = strchr(RP->wall_name, '_')) != NULL) {
*cp = 0;
joinedwalls = 1;
}
for (i = 0; i < RP->Xsize; i++)
for (j = 0; j < RP->Ysize; j++) {
if (layout[i][j] == '#') {
if (joinedwalls)
thiswall = pick_joined_wall(the_wall, layout, i, j, RP);
else
thiswall = arch_to_object(the_wall->arch);
thiswall->x = i;
thiswall->y = j;
thiswall->move_block = MOVE_ALL;
thiswall->move_allow = 0;
insert_ob_in_map(thiswall, map, thiswall, INS_NO_MERGE|INS_NO_WALK_ON);
}
}
}
}
/**
* Picks the right wall type for this square, to make it look nice,
* and have everything nicely joined. It uses the layout.
* @param the_wall
* wall we want to insert.
* @param layout
* @param i
* @param j
* where to insert.
* @param RP
* map parameters.
* @return
* correct wall archetype to fit on the square.
* @todo
* check if there isn't an equivalent function in the building code, merge?
*/
object *pick_joined_wall(object *the_wall, char **layout, int i, int j, RMParms *RP) {
/* 1 = wall to left,
2 = wall to right,
4 = wall above
8 = wall below */
int surround_index = 0;
int l;
char wall_name[64];
archetype *wall_arch = NULL;
strncpy(wall_name, the_wall->arch->name, sizeof(wall_name));
/* conventionally, walls are named like this:
wallname_wallcode, where wallcode indicates
a joinedness, and wallname is the wall.
this code depends on the convention for
finding the right wall. */
/* extract the wall name, which is the text up to the leading _ */
for (l = 0; l < 64; l++) {
if (wall_name[l] == '_') {
wall_name[l] = 0;
break;
}
}
surround_index = surround_flag2(layout, i, j, RP);
switch (surround_index) {
case 0:
strcat(wall_name, "_0");
break;
case 1:
strcat(wall_name, "_1_3");
break;
case 2:
strcat(wall_name, "_1_4");
break;
case 3:
strcat(wall_name, "_2_1_2");
break;
case 4:
strcat(wall_name, "_1_2");
break;
case 5:
strcat(wall_name, "_2_2_4");
break;
case 6:
strcat(wall_name, "_2_2_1");
break;
case 7:
strcat(wall_name, "_3_1");
break;
case 8:
strcat(wall_name, "_1_1");
break;
case 9:
strcat(wall_name, "_2_2_3");
break;
case 10:
strcat(wall_name, "_2_2_2");
break;
case 11:
strcat(wall_name, "_3_3");
break;
case 12:
strcat(wall_name, "_2_1_1");
break;
case 13:
strcat(wall_name, "_3_4");
break;
case 14:
strcat(wall_name, "_3_2");
break;
case 15:
strcat(wall_name, "_4");
break;
}
wall_arch = try_find_archetype(wall_name);
if (wall_arch)
return arch_to_object(wall_arch);
else {
return arch_to_object(the_wall->arch);
}
}
/**
* this takes a map, and changes an existing wall to match what's blocked
* around it, counting only doors and walls as blocked. If insert_flag is
* 1, . If not, it
* will only return the wall which would belong there, and doesn't
* remove anything. It depends on the
* global, previously-set variable, "wall_name"
* @param the_map
* @param i
* @param j
* where to look.
* @param insert_flag
* if 1, insert the correct wall into the map, else don't insert.
* @param RP
* map parameters.
* @return
* correct wall for spot.
* @todo
* merge with pick_joined_wall()?
*/
object *retrofit_joined_wall(mapstruct *the_map, int i, int j, int insert_flag, RMParms *RP) {
/* 1 = wall to left,
* 2 = wall to right,
* 4 = wall above
* 8 = wall below
*/
int surround_index = 0;
int l;
object *the_wall = NULL;
object *new_wall = NULL;
archetype *wall_arch = NULL;
/* first find the wall */
for (the_wall = GET_MAP_OB(the_map, i, j); the_wall != NULL; the_wall = the_wall->above)
if ((the_wall->move_type&MOVE_WALK) && the_wall->type != EXIT && the_wall->type != TELEPORTER)
break;
/* if what we found is a door, don't remove it, set the_wall to NULL to
* signal that later.
*/
if (the_wall && (the_wall->type == DOOR || the_wall->type == LOCKED_DOOR)) {
the_wall = NULL;
/* if we're not supposed to insert a new wall where there wasn't one,
* we've gotta leave.
*/
if (insert_flag == 0)
return NULL;
} else if (the_wall == NULL)
return NULL;
/* canonicalize the wall name */
for (l = 0; l < 64; l++) {
if (RP->wall_name[l] == '_') {
RP->wall_name[l] = 0;
break;
}
}
surround_index = surround_flag4(the_map, i, j, RP);
/* This would be a lot cleaner to just us a lookup table,
* eg, wall_suffix[surround_index]
*/
switch (surround_index) {
case 0:
strcat(RP->wall_name, "_0");
break;
case 1:
strcat(RP->wall_name, "_1_3");
break;
case 2:
strcat(RP->wall_name, "_1_4");
break;
case 3:
strcat(RP->wall_name, "_2_1_2");
break;
case 4:
strcat(RP->wall_name, "_1_2");
break;
case 5:
strcat(RP->wall_name, "_2_2_4");
break;
case 6:
strcat(RP->wall_name, "_2_2_1");
break;
case 7:
strcat(RP->wall_name, "_3_1");
break;
case 8:
strcat(RP->wall_name, "_1_1");
break;
case 9:
strcat(RP->wall_name, "_2_2_3");
break;
case 10:
strcat(RP->wall_name, "_2_2_2");
break;
case 11:
strcat(RP->wall_name, "_3_3");
break;
case 12:
strcat(RP->wall_name, "_2_1_1");
break;
case 13:
strcat(RP->wall_name, "_3_4");
break;
case 14:
strcat(RP->wall_name, "_3_2");
break;
case 15:
strcat(RP->wall_name, "_4");
break;
}
wall_arch = try_find_archetype(RP->wall_name);
if (wall_arch != NULL) {
new_wall = arch_to_object(wall_arch);
new_wall->x = i;
new_wall->y = j;
if (the_wall && the_wall->map) {
remove_ob(the_wall);
free_object(the_wall);
}
the_wall->move_block = MOVE_ALL;
insert_ob_in_map(new_wall, the_map, new_wall, INS_NO_MERGE|INS_NO_WALK_ON);
}
return new_wall;
}