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