ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/special.C
Revision: 1.4
Committed: Sun Sep 10 16:06:37 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +237 -193 lines
Log Message:
indent

File Contents

# Content
1
2 /*
3 * static char *rcsid_special_c =
4 * "$Id: special.C,v 1.3 2006-09-03 00:18:41 root Exp $";
5 */
6
7 /*
8 CrossFire, A Multiplayer game for X-windows
9
10 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 The authors can be reached via e-mail at crossfire-devel@real-time.com
28 */
29
30 /* Specials in this file:
31 included maps */
32
33 #include <global.h>
34 #include <random_map.h>
35 #include <rproto.h>
36
37 #define NUM_OF_SPECIAL_TYPES 4
38 #define NO_SPECIAL 0
39 #define SPECIAL_SUBMAP 1
40 #define SPECIAL_FOUNTAIN 2
41 #define SPECIAL_EXIT 3
42
43 #define GLORY_HOLE 1
44 #define ORC_ZONE 2
45 #define MINING_ZONE 3
46 #define NR_OF_HOLE_TYPES 3
47
48 /* clear map completely of all objects: a rectangular area of xsize, ysize
49 is cleared with the top left corner at xstart, ystart */
50
51 void
52 nuke_map_region (mapstruct *map, int xstart, int ystart, int xsize, int ysize)
53 {
54 int i, j;
55 object *tmp;
56
57 for (i = xstart; i < xstart + xsize; i++)
58 for (j = ystart; j < ystart + ysize; j++)
59 {
60 for (tmp = get_map_ob (map, i, j); tmp != NULL; tmp = tmp->above)
61 {
62 if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR))
63 {
64 if (tmp->head)
65 tmp = tmp->head;
66 remove_ob (tmp);
67 free_object (tmp);
68 tmp = get_map_ob (map, i, j);
69 }
70 if (tmp == NULL)
71 break;
72 }
73 }
74 }
75
76
77
78 /* copy in_map into dest_map at point x,y */
79
80
81 void
82 include_map_in_map (mapstruct *dest_map, mapstruct *in_map, int x, int y)
83 {
84 int i, j;
85 object *tmp;
86 object *new_ob;
87
88 /* First, splatter everything in the dest map at the location */
89 nuke_map_region (dest_map, x, y, MAP_WIDTH (in_map), MAP_HEIGHT (in_map));
90
91 for (i = 0; i < MAP_WIDTH (in_map); i++)
92 for (j = 0; j < MAP_HEIGHT (in_map); j++)
93 {
94 for (tmp = get_map_ob (in_map, i, j); tmp != NULL; tmp = tmp->above)
95 {
96 /* don't copy things with multiple squares: must be dealt with
97 specially. */
98 if (tmp->head != NULL)
99 continue;
100 new_ob = arch_to_object (tmp->arch);
101 copy_object_with_inv (tmp, new_ob);
102 if (QUERY_FLAG (tmp, FLAG_IS_LINKED))
103 add_button_link (new_ob, dest_map, tmp->path_attuned);
104 new_ob->x = i + x;
105 new_ob->y = j + y;
106 insert_multisquare_ob_in_map (new_ob, dest_map);
107 }
108 }
109 }
110
111 int
112 find_spot_for_submap (mapstruct *map, char **layout, int *ix, int *iy, int xsize, int ysize)
113 {
114 int tries;
115 int i = 0, j = 0; /* initialization may not be needed but prevents compiler warnings */
116 int is_occupied = 0;
117 int l, m;
118
119 /* don't even try to place a submap into a map if the big map isn't
120 sufficiently large. */
121 if (2 * xsize > MAP_WIDTH (map) || 2 * ysize > MAP_HEIGHT (map))
122 return 0;
123
124 /* search a bit for a completely free spot. */
125 for (tries = 0; tries < 20; tries++)
126 {
127 /* pick a random location in the layout */
128 i = RANDOM () % (MAP_WIDTH (map) - xsize - 2) + 1;
129 j = RANDOM () % (MAP_HEIGHT (map) - ysize - 2) + 1;
130 is_occupied = 0;
131 for (l = i; l < i + xsize; l++)
132 for (m = j; m < j + ysize; m++)
133 is_occupied |= layout[l][m];
134 if (!is_occupied)
135 break;
136 }
137
138
139 /* if we failed, relax the restrictions */
140
141 if (is_occupied)
142 { /* failure, try a relaxed placer. */
143 /* pick a random location in the layout */
144 for (tries = 0; tries < 10; tries++)
145 {
146 i = RANDOM () % (MAP_WIDTH (map) - xsize - 2) + 1;
147 j = RANDOM () % (MAP_HEIGHT (map) - ysize - 2) + 1;
148 is_occupied = 0;
149 for (l = i; l < i + xsize; l++)
150 for (m = j; m < j + ysize; m++)
151 if (layout[l][m] == 'C' || layout[l][m] == '>' || layout[l][m] == '<')
152 is_occupied |= 1;
153 }
154 }
155 if (is_occupied)
156 return 0;
157 *ix = i;
158 *iy = j;
159 return 1;
160 }
161
162
163 void
164 place_fountain_with_specials (mapstruct *map)
165 {
166 int ix, iy, i = -1, tries = 0;
167 mapstruct *fountain_style = find_style ("/styles/misc", "fountains", -1);
168 object *fountain = get_archetype ("fountain");
169 object *potion = get_object ();
170
171 copy_object (pick_random_object (fountain_style), potion);
172 while (i < 0 && tries < 10)
173 {
174 ix = RANDOM () % (MAP_WIDTH (map) - 2) + 1;
175 iy = RANDOM () % (MAP_HEIGHT (map) - 2) + 1;
176 i = find_first_free_spot (fountain, map, ix, iy);
177 tries++;
178 };
179 if (i == -1)
180 { /* can't place fountain */
181 free_object (fountain);
182 free_object (potion);
183 return;
184 }
185 ix += freearr_x[i];
186 iy += freearr_y[i];
187 potion->face = fountain->face;
188 SET_FLAG (potion, FLAG_NO_PICK);
189 SET_FLAG (potion, FLAG_IDENTIFIED);
190 potion->name = potion->name_pl = "fountain";
191 potion->x = ix;
192 potion->y = iy;
193 potion->material = M_ADAMANT;
194 fountain->x = ix;
195 fountain->y = iy;
196 insert_ob_in_map (fountain, map, NULL, 0);
197 insert_ob_in_map (potion, map, NULL, 0);
198
199 }
200
201 void
202 place_special_exit (mapstruct *map, int hole_type, RMParms * RP)
203 {
204 int ix, iy, i = -1;
205 char buf[HUGE_BUF], *style, *decor, *mon;
206 mapstruct *exit_style = find_style ("/styles/misc", "obscure_exits", -1);
207 int g_xsize, g_ysize;
208
209 object *the_exit = get_object ();
210
211 if (!exit_style)
212 return;
213
214 copy_object (pick_random_object (exit_style), the_exit);
215
216 while (i < 0)
217 {
218 ix = RANDOM () % (MAP_WIDTH (map) - 2) + 1;
219 iy = RANDOM () % (MAP_HEIGHT (map) - 2) + 1;
220 i = find_first_free_spot (the_exit, map, ix, iy);
221 }
222
223 ix += freearr_x[i];
224 iy += freearr_y[i];
225 the_exit->x = ix;
226 the_exit->y = iy;
227
228 if (!hole_type)
229 hole_type = RANDOM () % NR_OF_HOLE_TYPES + 1;
230
231 switch (hole_type)
232 {
233 case GLORY_HOLE: /* treasures */
234 {
235 g_xsize = RANDOM () % 3 + 4 + RP->difficulty / 4;
236 g_ysize = RANDOM () % 3 + 4 + RP->difficulty / 4;
237 style = "onion";
238 decor = "wealth2";
239 mon = "none";
240 break;
241 }
242
243 case ORC_ZONE: /* hole with orcs in it. */
244 {
245 g_xsize = RANDOM () % 3 + 4 + RP->difficulty / 4;
246 g_ysize = RANDOM () % 3 + 4 + RP->difficulty / 4;
247 style = "onion";
248 decor = "wealth2";
249 mon = "orc";
250 break;
251 }
252
253 case MINING_ZONE: /* hole with orcs in it. */
254 {
255 g_xsize = RANDOM () % 9 + 4 + RP->difficulty / 4;
256 g_ysize = RANDOM () % 9 + 4 + RP->difficulty / 4;
257 style = "maze";
258 decor = "minerals2";
259 mon = "none";
260 break;
261 }
262
263 default: /* undefined */
264 LOG (llevError, "place_special_exit: undefined hole type %d\n", hole_type);
265 return;
266 break;
267 }
268
269 /* Need to be at least this size, otherwise the load
270 * code will generate new size values which are too large.
271 */
272 if (g_xsize < MIN_RANDOM_MAP_SIZE)
273 g_xsize = MIN_RANDOM_MAP_SIZE;
274 if (g_ysize < MIN_RANDOM_MAP_SIZE)
275 g_ysize = MIN_RANDOM_MAP_SIZE;
276
277 write_parameters_to_string (buf, g_xsize, g_ysize, RP->wallstyle, RP->floorstyle, mon,
278 "none", style, decor, "none", RP->exitstyle, 0, 0, 0,
279 OPT_WALLS_ONLY, 0, 0, 1, RP->dungeon_level, RP->dungeon_level,
280 RP->difficulty, RP->difficulty, -1, 1, 0, 0, 0, 0, RP->difficulty_increase);
281 the_exit->slaying = "/!";
282 the_exit->msg = buf;
283
284 insert_ob_in_map (the_exit, map, NULL, 0);
285 }
286
287
288 void
289 place_specials_in_map (mapstruct *map, char **layout, RMParms * RP)
290 {
291 mapstruct *special_map;
292 int ix, iy; /* map insertion locatons */
293 int special_type; /* type of special to make */
294
295
296 special_type = RANDOM () % NUM_OF_SPECIAL_TYPES;
297 switch (special_type)
298 {
299
300 /* includes a special map into the random map being made. */
301 case SPECIAL_SUBMAP:
302 {
303 special_map = find_style ("/styles/specialmaps", 0, RP->difficulty);
304 if (special_map == NULL)
305 return;
306
307 if (find_spot_for_submap (map, layout, &ix, &iy, MAP_WIDTH (special_map), MAP_HEIGHT (special_map)))
308 include_map_in_map (map, special_map, ix, iy);
309 break;
310 }
311
312 /* Make a special fountain: an unpickable potion disguised as
313 a fountain, or rather, colocated with a fountain. */
314 case SPECIAL_FOUNTAIN:
315 {
316 place_fountain_with_specials (map);
317 break;
318 }
319
320 /* Make an exit to another random map, e.g. a gloryhole. */
321 case SPECIAL_EXIT:
322 {
323 place_special_exit (map, 0, RP);
324 break;
325 }
326 }
327
328 }