/* * CrossFire, A Multiplayer game for X-windows * * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team * 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 */ #include #include #include /* Put in the walls and autojoin them. */ /* given a layout and a coordinate, tell me which squares up/down/right/left are occupied. */ int surround_flag (char **layout, int i, int j, random_map_params *RP) { /* 1 = wall to left, 2 = wall to right, 4 = wall above 8 = wall below */ 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; } /* like surround_flag, but only walls count. */ int surround_flag2 (char **layout, int i, int j, random_map_params *RP) { /* 1 = wall to left, 2 = wall to right, 4 = wall above 8 = wall below */ 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; } /* like surround_flag, except it checks a map, not a layout. * 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. */ int surround_flag3 (maptile *map, sint16 i, sint16 j, random_map_params *RP) { /* * 1 = blocked to left, * 2 = blocked to right, * 4 = blocked above * 8 = blocked below */ 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; } /* like surround_flag2, except it checks a map, not a layout. */ int surround_flag4 (maptile *map, int i, int j, random_map_params *RP) { /* 1 = blocked to left, 2 = blocked to right, 4 = blocked above 8 = blocked below */ 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. */ void make_map_walls (maptile *map, char **layout, char *w_style, random_map_params *RP) { char styledirname[1024]; char stylefilepath[1024]; maptile *style_map = 0; object *the_wall; /* get the style map */ if (!strcmp (w_style, "none")) return; sprintf (styledirname, "%s", "/styles/wallstyles"); sprintf (stylefilepath, "%s/%s", styledirname, w_style); style_map = find_style (styledirname, w_style, -1); if (!style_map) 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; sprintf (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; 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. */ object * pick_joined_wall (object *the_wall, char **layout, int i, int j, random_map_params *RP) { /* 1 = wall to left, 2 = wall to right, 4 = wall above 8 = wall below */ int surround_index = 0; int l; char wall_name[1024]; archetype *wall_arch = 0; assign (wall_name, the_wall->arch->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 = archetype::find (wall_name); return wall_arch ? arch_to_object (wall_arch) : 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, it will go ahead and insert the wall into the map. 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" */ object * retrofit_joined_wall (maptile *the_map, int i, int j, int insert_flag, random_map_params *RP) { /* 1 = wall to left, * 2 = wall to right, * 4 = wall above * 8 = wall below */ int surround_index = 0; int l; object *the_wall = 0; object *new_wall = 0; archetype *wall_arch = 0; /* 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 0; } 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 = archetype::find (RP->wall_name); if (!wall_arch) { new_wall = arch_to_object (wall_arch); new_wall->x = i; new_wall->y = j; if (the_wall && the_wall->map) { the_wall->remove (); the_wall->destroy (); } 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; }