ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/exit.C
Revision: 1.57
Committed: Sat Nov 17 23:40:02 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.56: +1 -0 lines
Log Message:
copyright update 2018

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
7 * Copyright (©) 1992 Frank Tore Johansen
8 *
9 * Deliantra is free software: you can redistribute it and/or modify it under
10 * the terms of the Affero GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the Affero GNU General Public License
20 * and the GNU General Public License along with this program. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 * The authors can be reached via e-mail to <support@deliantra.net>
24 */
25
26 #include <global.h>
27 #include <rmg.h>
28 #include <sproto.h>
29 #include <rproto.h>
30
31 /* find a character in the maze. fx and fy are pointers to
32 where to find the char. fx,fy = -1 if not found. */
33 static void
34 find_in_layout (int mode, char target, int &fx, int &fy, layout &maze)
35 {
36 int M;
37 int i, j;
38
39 fx = -1;
40 fy = -1;
41
42 /* if a starting point isn't given, pick one */
43 if (mode < 1 || mode > 4)
44 M = rmg_rndm (4) + 1;
45 else
46 M = mode;
47
48 /* four different search starting points and methods so that
49 we can do something different for symmetrical maps instead of
50 the same damned thing every time. */
51 switch (M)
52 {
53 case 1:
54 /* search from top left down/right */
55 for (i = 1; i < maze.w; i++)
56 for (j = 1; j < maze.h; j++)
57 {
58 if (maze[i][j] == target)
59 {
60 fx = i;
61 fy = j;
62 return;
63 }
64 }
65 break;
66
67 case 2:
68 /* Search from top right down/left */
69 for (i = maze.w - 2; i > 0; i--)
70 for (j = 1; j < maze.h - 1; j++)
71 {
72 if (maze[i][j] == target)
73 {
74 fx = i;
75 fy = j;
76 return;
77 }
78 }
79 break;
80
81 case 3:
82 /* search from bottom-right up-left */
83 for (i = maze.w - 2; i > 0; i--)
84 for (j = maze.h - 2; j > 0; j--)
85 {
86 if (maze[i][j] == target)
87 {
88 fx = i;
89 fy = j;
90 return;
91 }
92 }
93 break;
94
95 case 4:
96 /* search from bottom-left up-right */
97 for (i = 1; i < maze.w - 1; i++)
98 for (j = maze.h - 2; j > 0; j--)
99 {
100 if (maze[i][j] == target)
101 {
102 fx = i;
103 fy = j;
104 return;
105 }
106 }
107 break;
108 }
109 }
110
111 point
112 layout::find (char target, int mode)
113 {
114 int x, y;
115
116 find_in_layout (mode, target, x, y, *this);
117
118 return point (x, y);
119 }
120
121 /* orientation: 0 means random,
122 1 means descending dungeon
123 2 means ascending dungeon
124 3 means rightward
125 4 means leftward
126 5 means northward
127 6 means southward
128 */
129 void
130 place_exits (maptile *map, layout &maze, const char *exitstyle, int orientation, random_map_params *RP)
131 {
132 maptile *style_map_down = 0; /* harder maze */
133 maptile *style_map_up = 0; /* easier maze */
134 object *the_exit_down; /* harder maze */
135 object *the_exit_up; /* easier maze */
136 int cx = -1, cy = -1; /* location of a map center */
137 int upx = -1, upy = -1; /* location of up exit */
138 int downx = -1, downy = -1;
139 int final_map_exit = 1;
140
141 if (const char *eofm = RP->get_str ("exit_on_final_map", 0))
142 if (strstr (eofm, "no"))
143 final_map_exit = 0;
144
145 if (!orientation)
146 orientation = rmg_rndm (6) + 1;
147
148 switch (orientation)
149 {
150 case 1:
151 {
152 style_map_up = find_style ("/styles/exitstyles/up" , exitstyle, RP->difficulty);
153 style_map_down = find_style ("/styles/exitstyles/down", exitstyle, RP->difficulty);
154 break;
155 }
156
157 case 2:
158 {
159 style_map_up = find_style ("/styles/exitstyles/down", exitstyle, RP->difficulty);
160 style_map_down = find_style ("/styles/exitstyles/up" , exitstyle, RP->difficulty);
161 break;
162 }
163
164 default:
165 {
166 style_map_up =
167 style_map_down = find_style ("/styles/exitstyles/generic", exitstyle, RP->difficulty);
168 break;
169 }
170 }
171
172 the_exit_up = style_map_up
173 ? style_map_up->pick_random_object (rmg_rndm)->clone ()
174 : archetype::get (shstr_exit);
175
176 const char *final_map = RP->get_str ("final_map", 0);
177
178 /* we need a down exit only if we're recursing. */
179 if (RP->dungeon_level < RP->dungeon_depth || final_map)
180 the_exit_down = style_map_down
181 ? style_map_down->pick_random_object (rmg_rndm)->clone ()
182 : archetype::get (shstr_exit);
183 else
184 the_exit_down = 0;
185
186 /* set up the up exit */
187 the_exit_up->stats.hp = RP->get_iv ("origin_x", -1);
188 the_exit_up->stats.sp = RP->get_iv ("origin_y", -1);
189 the_exit_up->slaying = RP->get_str ("origin_map", 0);
190
191 /* figure out where to put the entrance */
192 /* begin a logical block */
193 {
194 /* First, look for a '<' char */
195 find_in_layout (0, '<', upx, upy, maze);
196
197 /* next, look for a C, the map center. */
198 find_in_layout (0, 'C', cx, cy, maze);
199
200 /* if we didn't find an up, find an empty place far from the center */
201 if (upx == -1 && cx != -1)
202 {
203 if (cx > RP->Xsize / 2)
204 upx = 1;
205 else
206 upx = RP->Xsize - 2;
207
208 if (cy > RP->Ysize / 2)
209 upy = 1;
210 else
211 upy = RP->Ysize - 2;
212
213 /* find an empty place far from the center */
214 if (upx == 1 && upy == 1) find_in_layout (1, 0, upx, upy, maze);
215 else if (upx > 1 && upy == 1) find_in_layout (2, 0, upx, upy, maze);
216 else if (upx > 1 && upy > 1) find_in_layout (3, 0, upx, upy, maze);
217 else if (upx == 1 && upy > 1) find_in_layout (4, 0, upx, upy, maze);
218 }
219
220 /* no indication of where to place the exit, so just place it. */
221 if (upx == -1)
222 find_in_layout (0, 0, upx, upy, maze);
223
224 the_exit_up->x = upx;
225 the_exit_up->y = upy;
226
227 /* surround the exits with notices that this is a random map. */
228 for (int j = 1; j < 9; j++)
229 if (!wall_blocked (map, the_exit_up->x + DIRX (j), the_exit_up->y + DIRY (j)))
230 {
231 object *random_sign = archetype::get (shstr_sign);
232 random_sign->msg = format ("This is a random map.\nLevel: %d of %d.\n", RP->dungeon_level - 1, RP->dungeon_depth);
233 map->insert (random_sign, the_exit_up->x + DIRX (j), the_exit_up->y + DIRY (j), 0, 0);
234 }
235
236 /* Block the exit so things don't get dumped on top of it. */
237 the_exit_up->move_block = MOVE_ALL;
238
239 insert_ob_in_map (the_exit_up, map, NULL, 0);
240 maze[the_exit_up->x][the_exit_up->y] = '<';
241
242 /* set the starting x,y for this map */
243 map->enter_x = the_exit_up->x;
244 map->enter_y = the_exit_up->y;
245
246 /* first, look for a '>' character */
247 find_in_layout (0, '>', downx, downy, maze);
248
249 /* if no > is found use C */
250 if (downx == -1)
251 {
252 downx = cx;
253 downy = cy;
254 };
255
256 /* make the other exit far away from this one if
257 there's no center. */
258 if (downx == -1)
259 {
260 if (upx > RP->Xsize / 2)
261 downx = 1;
262 else
263 downx = RP->Xsize - 2;
264
265 if (upy > RP->Ysize / 2)
266 downy = 1;
267 else
268 downy = RP->Ysize - 2;
269
270 /* find an empty place far from the entrance */
271 if (downx == 1 && downy == 1) find_in_layout (1, 0, downx, downy, maze);
272 else if (downx > 1 && downy == 1) find_in_layout (2, 0, downx, downy, maze);
273 else if (downx > 1 && downy > 1) find_in_layout (3, 0, downx, downy, maze);
274 else if (downx == 1 && downy > 1) find_in_layout (4, 0, downx, downy, maze);
275 }
276
277 /* no indication of where to place the down exit, so just place it */
278 if (downx == -1)
279 find_in_layout (0, 0, downx, downy, maze);
280
281 if (the_exit_down)
282 {
283 int i = rmg_find_free_spot (the_exit_down, map, downx, downy, 1, SIZEOFFREE1 + 1);
284
285 the_exit_down->x = downx + DIRX (i);
286 the_exit_down->y = downy + DIRY (i);
287
288 RP->set ("origin_x", (IV)the_exit_down->x);
289 RP->set ("origin_y", (IV)the_exit_down->y);
290
291 the_exit_down->msg = RP->as_shstr ();
292 the_exit_down->slaying = shstr_random_map_exit;
293
294 /* the identifier for making a random map. */
295 if (RP->dungeon_level >= RP->dungeon_depth && final_map)
296 {
297 the_exit_down->msg = 0;
298 the_exit_down->slaying = final_map;
299
300 if (final_map_exit)
301 if (maptile *new_map = maptile::find_sync (final_map))
302 {
303 object *the_exit_back = the_exit_up->arch->instance ();
304
305 new_map->load_sync ();
306
307 for (object *tmp = new_map->at (new_map->enter_x, new_map->enter_y).bot; tmp; tmp = tmp->above)
308 /* Remove exit back to previous random map. There should only be one
309 * which is why we break out. To try to process more than one
310 * would require keeping a 'next' pointer, ad free_object kills tmp, which
311 * breaks the for loop.
312 */
313 if (tmp->type == EXIT && EXIT_PATH (tmp).starts_with ("?random/"))
314 {
315 tmp->destroy ();
316 break;
317 }
318
319 /* setup the exit back */
320 the_exit_back->slaying = map->path;
321 the_exit_back->stats.hp = the_exit_down->x;
322 the_exit_back->stats.sp = the_exit_down->y;
323 the_exit_back->x = new_map->enter_x;
324 the_exit_back->y = new_map->enter_y;
325
326 insert_ob_in_map (the_exit_back, new_map, NULL, 0);
327 }
328 }
329
330 /* Block the exit so things don't get dumped on top of it. */
331 the_exit_down->move_block = MOVE_ALL;
332 insert_ob_in_map (the_exit_down, map, NULL, 0);
333 maze[the_exit_down->x][the_exit_down->y] = '>';
334 }
335 }
336 }
337
338 /* this function unblocks the exits. We blocked them to
339 keep things from being dumped on them during the other
340 phases of random map generation. */
341 void
342 unblock_exits (maptile *map, layout &maze)
343 {
344 int i = 0, j = 0;
345 object *walk;
346
347 for (i = 0; i < maze.w; i++)
348 for (j = 0; j < maze.h; j++)
349 if (maze[i][j] == '>' || maze[i][j] == '<')
350 {
351 for (walk = GET_MAP_OB (map, i, j); walk != NULL; walk = walk->above)
352 {
353 if (walk->move_block == MOVE_ALL && walk->type != LOCKED_DOOR)
354 {
355 walk->move_block = 0;
356 update_object (walk, UP_OBJ_CHANGE);
357 }
358 }
359 }
360 }
361