1 /* NetHack 3.6 sp_lev.c $NHDT-Date: 1567805254 2019/09/06 21:27:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.117 $ */
2 /* Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /*
6 * This file contains the various functions that are related to the special
7 * levels.
8 *
9 * It contains also the special level loader.
10 */
11
12 #include "hack.h"
13 #include "dlb.h"
14 #include "sp_lev.h"
15
16 #ifdef _MSC_VER
17 #pragma warning(push)
18 #pragma warning(disable : 4244)
19 #endif
20
21 typedef void FDECL((*select_iter_func), (int, int, genericptr));
22
23 extern void FDECL(mkmap, (lev_init *));
24
25 STATIC_DCL void NDECL(solidify_map);
26 STATIC_DCL void FDECL(splev_stack_init, (struct splevstack *));
27 STATIC_DCL void FDECL(splev_stack_done, (struct splevstack *));
28 STATIC_DCL void FDECL(splev_stack_push, (struct splevstack *,
29 struct opvar *));
30 STATIC_DCL struct opvar *FDECL(splev_stack_pop, (struct splevstack *));
31 STATIC_DCL struct splevstack *FDECL(splev_stack_reverse,
32 (struct splevstack *));
33 STATIC_DCL struct opvar *FDECL(opvar_new_str, (char *));
34 STATIC_DCL struct opvar *FDECL(opvar_new_int, (long));
35 STATIC_DCL struct opvar *FDECL(opvar_new_coord, (int, int));
36 #if 0
37 STATIC_DCL struct opvar * FDECL(opvar_new_region, (int,int, int,int));
38 #endif /*0*/
39 STATIC_DCL struct opvar *FDECL(opvar_clone, (struct opvar *));
40 STATIC_DCL struct opvar *FDECL(opvar_var_conversion, (struct sp_coder *,
41 struct opvar *));
42 STATIC_DCL struct splev_var *FDECL(opvar_var_defined, (struct sp_coder *,
43 char *));
44 STATIC_DCL struct opvar *FDECL(splev_stack_getdat, (struct sp_coder *,
45 XCHAR_P));
46 STATIC_DCL struct opvar *FDECL(splev_stack_getdat_any, (struct sp_coder *));
47 STATIC_DCL void FDECL(variable_list_del, (struct splev_var *));
48 STATIC_DCL void FDECL(lvlfill_maze_grid, (int, int, int, int, SCHAR_P));
49 STATIC_DCL void FDECL(lvlfill_solid, (SCHAR_P, SCHAR_P));
50 STATIC_DCL void FDECL(set_wall_property, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P,
51 int));
52 STATIC_DCL void NDECL(shuffle_alignments);
53 STATIC_DCL void NDECL(count_features);
54 STATIC_DCL void NDECL(remove_boundary_syms);
55 STATIC_DCL void FDECL(set_door_orientation, (int, int));
56 STATIC_DCL void FDECL(maybe_add_door, (int, int, struct mkroom *));
57 STATIC_DCL void NDECL(link_doors_rooms);
58 STATIC_DCL void NDECL(fill_rooms);
59 STATIC_DCL int NDECL(rnddoor);
60 STATIC_DCL int NDECL(rndtrap);
61 STATIC_DCL void FDECL(get_location, (schar *, schar *, int, struct mkroom *));
62 STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
63 STATIC_DCL unpacked_coord FDECL(get_unpacked_coord, (long, int));
64 STATIC_DCL void FDECL(get_location_coord, (schar *, schar *, int,
65 struct mkroom *, long));
66 STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
67 STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *,
68 struct mkroom *, packed_coord));
69 STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
70 XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
71 STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
72 STATIC_DCL void FDECL(create_trap, (spltrap *, struct mkroom *));
73 STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
74 STATIC_DCL boolean FDECL(m_bad_boulder_spot, (int, int));
75 STATIC_DCL int FDECL(pm_to_humidity, (struct permonst *));
76 STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
77 STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
78 STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
79 STATIC_DCL void FDECL(replace_terrain, (replaceterrain *, struct mkroom *));
80 STATIC_DCL boolean FDECL(search_door, (struct mkroom *,
81 xchar *, xchar *, XCHAR_P, int));
82 STATIC_DCL void NDECL(fix_stair_rooms);
83 STATIC_DCL void FDECL(create_corridor, (corridor *));
84 STATIC_DCL struct mkroom *FDECL(build_room, (room *, struct mkroom *));
85 STATIC_DCL void FDECL(light_region, (region *));
86 STATIC_DCL void FDECL(wallify_map, (int, int, int, int));
87 STATIC_DCL void FDECL(maze1xy, (coord *, int));
88 STATIC_DCL void NDECL(fill_empty_maze);
89 STATIC_DCL boolean FDECL(sp_level_loader, (dlb *, sp_lev *));
90 STATIC_DCL boolean FDECL(sp_level_free, (sp_lev *));
91 STATIC_DCL void FDECL(splev_initlev, (lev_init *));
92 STATIC_DCL struct sp_frame *FDECL(frame_new, (long));
93 STATIC_DCL void FDECL(frame_del, (struct sp_frame *));
94 STATIC_DCL void FDECL(spo_frame_push, (struct sp_coder *));
95 STATIC_DCL void FDECL(spo_frame_pop, (struct sp_coder *));
96 STATIC_DCL long FDECL(sp_code_jmpaddr, (long, long));
97 STATIC_DCL void FDECL(spo_call, (struct sp_coder *));
98 STATIC_DCL void FDECL(spo_return, (struct sp_coder *));
99 STATIC_DCL void FDECL(spo_end_moninvent, (struct sp_coder *));
100 STATIC_DCL void FDECL(spo_pop_container, (struct sp_coder *));
101 STATIC_DCL void FDECL(spo_message, (struct sp_coder *));
102 STATIC_DCL void FDECL(spo_monster, (struct sp_coder *));
103 STATIC_DCL void FDECL(spo_object, (struct sp_coder *));
104 STATIC_DCL void FDECL(spo_level_flags, (struct sp_coder *));
105 STATIC_DCL void FDECL(spo_initlevel, (struct sp_coder *));
106 STATIC_DCL void FDECL(spo_engraving, (struct sp_coder *));
107 STATIC_DCL void FDECL(spo_mineralize, (struct sp_coder *));
108 STATIC_DCL void FDECL(spo_room, (struct sp_coder *));
109 STATIC_DCL void FDECL(spo_endroom, (struct sp_coder *));
110 STATIC_DCL void FDECL(spo_stair, (struct sp_coder *));
111 STATIC_DCL void FDECL(spo_ladder, (struct sp_coder *));
112 STATIC_DCL void FDECL(spo_grave, (struct sp_coder *));
113 STATIC_DCL void FDECL(spo_altar, (struct sp_coder *));
114 STATIC_DCL void FDECL(spo_trap, (struct sp_coder *));
115 STATIC_DCL void FDECL(spo_gold, (struct sp_coder *));
116 STATIC_DCL void FDECL(spo_corridor, (struct sp_coder *));
117 STATIC_DCL void FDECL(selection_setpoint, (int, int, struct opvar *, XCHAR_P));
118 STATIC_DCL struct opvar *FDECL(selection_not, (struct opvar *));
119 STATIC_DCL struct opvar *FDECL(selection_logical_oper, (struct opvar *,
120 struct opvar *, CHAR_P));
121 STATIC_DCL struct opvar *FDECL(selection_filter_mapchar, (struct opvar *,
122 struct opvar *));
123 STATIC_DCL void FDECL(selection_filter_percent, (struct opvar *, int));
124 STATIC_DCL int FDECL(selection_rndcoord, (struct opvar *, schar *, schar *,
125 BOOLEAN_P));
126 STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int));
127 STATIC_DCL int FDECL(floodfillchk_match_under, (int, int));
128 STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int));
129 STATIC_DCL boolean FDECL(sel_flood_havepoint, (int, int,
130 xchar *, xchar *, int));
131 STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int,
132 int, int, int));
133 STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long));
134 STATIC_DCL void FDECL(selection_do_gradient, (struct opvar *, long, long, long,
135 long, long, long, long, long));
136 STATIC_DCL void FDECL(selection_do_line, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P,
137 struct opvar *));
138 STATIC_DCL void FDECL(selection_do_randline, (SCHAR_P, SCHAR_P, SCHAR_P,
139 SCHAR_P, SCHAR_P, SCHAR_P,
140 struct opvar *));
141 STATIC_DCL void FDECL(selection_iterate, (struct opvar *, select_iter_func,
142 genericptr_t));
143 STATIC_DCL void FDECL(sel_set_ter, (int, int, genericptr_t));
144 STATIC_DCL void FDECL(sel_set_feature, (int, int, genericptr_t));
145 STATIC_DCL void FDECL(sel_set_door, (int, int, genericptr_t));
146 STATIC_DCL void FDECL(spo_door, (struct sp_coder *));
147 STATIC_DCL void FDECL(spo_feature, (struct sp_coder *));
148 STATIC_DCL void FDECL(spo_terrain, (struct sp_coder *));
149 STATIC_DCL void FDECL(spo_replace_terrain, (struct sp_coder *));
150 STATIC_DCL boolean FDECL(generate_way_out_method, (int, int, struct opvar *));
151 STATIC_DCL void NDECL(ensure_way_out);
152 STATIC_DCL void FDECL(spo_levregion, (struct sp_coder *));
153 STATIC_DCL void FDECL(spo_region, (struct sp_coder *));
154 STATIC_DCL void FDECL(spo_drawbridge, (struct sp_coder *));
155 STATIC_DCL void FDECL(spo_mazewalk, (struct sp_coder *));
156 STATIC_DCL void FDECL(spo_wall_property, (struct sp_coder *));
157 STATIC_DCL void FDECL(spo_room_door, (struct sp_coder *));
158 STATIC_DCL void FDECL(sel_set_wallify, (int, int, genericptr_t));
159 STATIC_DCL void FDECL(spo_wallify, (struct sp_coder *));
160 STATIC_DCL void FDECL(spo_map, (struct sp_coder *));
161 STATIC_DCL void FDECL(spo_jmp, (struct sp_coder *, sp_lev *));
162 STATIC_DCL void FDECL(spo_conditional_jump, (struct sp_coder *, sp_lev *));
163 STATIC_DCL void FDECL(spo_var_init, (struct sp_coder *));
164 #if 0
165 STATIC_DCL long FDECL(opvar_array_length, (struct sp_coder *));
166 #endif /*0*/
167 STATIC_DCL void FDECL(spo_shuffle_array, (struct sp_coder *));
168 STATIC_DCL boolean FDECL(sp_level_coder, (sp_lev *));
169
170 #define LEFT 1
171 #define H_LEFT 2
172 #define CENTER 3
173 #define H_RIGHT 4
174 #define RIGHT 5
175
176 #define TOP 1
177 #define BOTTOM 5
178
179 #define sq(x) ((x) * (x))
180
181 #define XLIM 4
182 #define YLIM 3
183
184 #define Fread (void) dlb_fread
185 #define Fgetc (schar) dlb_fgetc
186 #define New(type) (type *) alloc(sizeof(type))
187 #define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned) size)
188 #define Free(ptr) if (ptr) free((genericptr_t) (ptr))
189
190 extern struct engr *head_engr;
191
192 extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
193
194 /* positions touched by level elements explicitly defined in the des-file */
195 static char SpLev_Map[COLNO][ROWNO];
196
197 static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
198 static NEARDATA xchar xstart, ystart;
199 static NEARDATA char xsize, ysize;
200
201 char *lev_message = 0;
202 lev_region *lregions = 0;
203 int num_lregions = 0;
204
205 static boolean splev_init_present = FALSE;
206 static boolean icedpools = FALSE;
207 static int mines_prize_count = 0, soko_prize_count = 0; /* achievements */
208
209 static struct obj *container_obj[MAX_CONTAINMENT];
210 static int container_idx = 0;
211 static struct monst *invent_carrying_monster = NULL;
212
213 #define SPLEV_STACK_RESERVE 128
214
215 void
solidify_map()216 solidify_map()
217 {
218 xchar x, y;
219
220 for (x = 0; x < COLNO; x++)
221 for (y = 0; y < ROWNO; y++)
222 if (IS_STWALL(levl[x][y].typ) && !SpLev_Map[x][y])
223 levl[x][y].wall_info |= (W_NONDIGGABLE | W_NONPASSWALL);
224 }
225
226 void
splev_stack_init(st)227 splev_stack_init(st)
228 struct splevstack *st;
229 {
230 if (st) {
231 st->depth = 0;
232 st->depth_alloc = SPLEV_STACK_RESERVE;
233 st->stackdata =
234 (struct opvar **) alloc(st->depth_alloc * sizeof (struct opvar *));
235 }
236 }
237
238 void
splev_stack_done(st)239 splev_stack_done(st)
240 struct splevstack *st;
241 {
242 if (st) {
243 int i;
244
245 if (st->stackdata && st->depth) {
246 for (i = 0; i < st->depth; i++) {
247 switch (st->stackdata[i]->spovartyp) {
248 default:
249 case SPOVAR_NULL:
250 case SPOVAR_COORD:
251 case SPOVAR_REGION:
252 case SPOVAR_MAPCHAR:
253 case SPOVAR_MONST:
254 case SPOVAR_OBJ:
255 case SPOVAR_INT:
256 break;
257 case SPOVAR_VARIABLE:
258 case SPOVAR_STRING:
259 case SPOVAR_SEL:
260 Free(st->stackdata[i]->vardata.str);
261 st->stackdata[i]->vardata.str = NULL;
262 break;
263 }
264 Free(st->stackdata[i]);
265 st->stackdata[i] = NULL;
266 }
267 }
268 Free(st->stackdata);
269 st->stackdata = NULL;
270 st->depth = st->depth_alloc = 0;
271 Free(st);
272 }
273 }
274
275 void
splev_stack_push(st,v)276 splev_stack_push(st, v)
277 struct splevstack *st;
278 struct opvar *v;
279 {
280 if (!st || !v)
281 return;
282 if (!st->stackdata)
283 panic("splev_stack_push: no stackdata allocated?");
284
285 if (st->depth >= st->depth_alloc) {
286 struct opvar **tmp = (struct opvar **) alloc(
287 (st->depth_alloc + SPLEV_STACK_RESERVE) * sizeof (struct opvar *));
288
289 (void) memcpy(tmp, st->stackdata,
290 st->depth_alloc * sizeof(struct opvar *));
291 Free(st->stackdata);
292 st->stackdata = tmp;
293 st->depth_alloc += SPLEV_STACK_RESERVE;
294 }
295
296 st->stackdata[st->depth] = v;
297 st->depth++;
298 }
299
300 struct opvar *
splev_stack_pop(st)301 splev_stack_pop(st)
302 struct splevstack *st;
303 {
304 struct opvar *ret = NULL;
305
306 if (!st)
307 return ret;
308 if (!st->stackdata)
309 panic("splev_stack_pop: no stackdata allocated?");
310
311 if (st->depth) {
312 st->depth--;
313 ret = st->stackdata[st->depth];
314 st->stackdata[st->depth] = NULL;
315 return ret;
316 } else
317 impossible("splev_stack_pop: empty stack?");
318 return ret;
319 }
320
321 struct splevstack *
splev_stack_reverse(st)322 splev_stack_reverse(st)
323 struct splevstack *st;
324 {
325 long i;
326 struct opvar *tmp;
327
328 if (!st)
329 return NULL;
330 if (!st->stackdata)
331 panic("splev_stack_reverse: no stackdata allocated?");
332 for (i = 0; i < (st->depth / 2); i++) {
333 tmp = st->stackdata[i];
334 st->stackdata[i] = st->stackdata[st->depth - i - 1];
335 st->stackdata[st->depth - i - 1] = tmp;
336 }
337 return st;
338 }
339
340 #define OV_typ(o) (o->spovartyp)
341 #define OV_i(o) (o->vardata.l)
342 #define OV_s(o) (o->vardata.str)
343
344 #define OV_pop_i(x) (x = splev_stack_getdat(coder, SPOVAR_INT))
345 #define OV_pop_c(x) (x = splev_stack_getdat(coder, SPOVAR_COORD))
346 #define OV_pop_r(x) (x = splev_stack_getdat(coder, SPOVAR_REGION))
347 #define OV_pop_s(x) (x = splev_stack_getdat(coder, SPOVAR_STRING))
348 #define OV_pop(x) (x = splev_stack_getdat_any(coder))
349 #define OV_pop_typ(x, typ) (x = splev_stack_getdat(coder, typ))
350
351 struct opvar *
opvar_new_str(s)352 opvar_new_str(s)
353 char *s;
354 {
355 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
356
357 tmpov->spovartyp = SPOVAR_STRING;
358 if (s) {
359 int len = strlen(s);
360 tmpov->vardata.str = (char *) alloc(len + 1);
361 (void) memcpy((genericptr_t) tmpov->vardata.str, (genericptr_t) s,
362 len);
363 tmpov->vardata.str[len] = '\0';
364 } else
365 tmpov->vardata.str = NULL;
366 return tmpov;
367 }
368
369 struct opvar *
opvar_new_int(i)370 opvar_new_int(i)
371 long i;
372 {
373 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
374
375 tmpov->spovartyp = SPOVAR_INT;
376 tmpov->vardata.l = i;
377 return tmpov;
378 }
379
380 struct opvar *
opvar_new_coord(x,y)381 opvar_new_coord(x, y)
382 int x, y;
383 {
384 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
385
386 tmpov->spovartyp = SPOVAR_COORD;
387 tmpov->vardata.l = SP_COORD_PACK(x, y);
388 return tmpov;
389 }
390
391 #if 0
392 struct opvar *
393 opvar_new_region(x1,y1,x2,y2)
394 int x1,y1,x2,y2;
395 {
396 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
397
398 tmpov->spovartyp = SPOVAR_REGION;
399 tmpov->vardata.l = SP_REGION_PACK(x1,y1,x2,y2);
400 return tmpov;
401 }
402 #endif /*0*/
403
404 void
opvar_free_x(ov)405 opvar_free_x(ov)
406 struct opvar *ov;
407 {
408 if (!ov)
409 return;
410 switch (ov->spovartyp) {
411 case SPOVAR_COORD:
412 case SPOVAR_REGION:
413 case SPOVAR_MAPCHAR:
414 case SPOVAR_MONST:
415 case SPOVAR_OBJ:
416 case SPOVAR_INT:
417 break;
418 case SPOVAR_VARIABLE:
419 case SPOVAR_STRING:
420 case SPOVAR_SEL:
421 Free(ov->vardata.str);
422 break;
423 default:
424 impossible("Unknown opvar value type (%i)!", ov->spovartyp);
425 }
426 Free(ov);
427 }
428
429 /*
430 * Name of current function for use in messages:
431 * __func__ -- C99 standard;
432 * __FUNCTION__ -- gcc extension, starting before C99 and continuing after;
433 * picked up by other compilers (or vice versa?);
434 * __FUNC__ -- supported by Borland;
435 * nhFunc -- slightly intrusive but fully portable nethack construct
436 * for any version of any compiler.
437 */
438 #define opvar_free(ov) \
439 do { \
440 if (ov) { \
441 opvar_free_x(ov); \
442 ov = NULL; \
443 } else \
444 impossible("opvar_free(), %s", nhFunc); \
445 } while (0)
446
447 struct opvar *
opvar_clone(ov)448 opvar_clone(ov)
449 struct opvar *ov;
450 {
451 struct opvar *tmpov;
452
453 if (!ov)
454 panic("no opvar to clone");
455 tmpov = (struct opvar *) alloc(sizeof(struct opvar));
456 tmpov->spovartyp = ov->spovartyp;
457 switch (ov->spovartyp) {
458 case SPOVAR_COORD:
459 case SPOVAR_REGION:
460 case SPOVAR_MAPCHAR:
461 case SPOVAR_MONST:
462 case SPOVAR_OBJ:
463 case SPOVAR_INT:
464 tmpov->vardata.l = ov->vardata.l;
465 break;
466 case SPOVAR_VARIABLE:
467 case SPOVAR_STRING:
468 case SPOVAR_SEL:
469 tmpov->vardata.str = dupstr(ov->vardata.str);
470 break;
471 default:
472 impossible("Unknown push value type (%i)!", ov->spovartyp);
473 }
474 return tmpov;
475 }
476
477 struct opvar *
opvar_var_conversion(coder,ov)478 opvar_var_conversion(coder, ov)
479 struct sp_coder *coder;
480 struct opvar *ov;
481 {
482 static const char nhFunc[] = "opvar_var_conversion";
483 struct splev_var *tmp;
484 struct opvar *tmpov;
485 struct opvar *array_idx = NULL;
486
487 if (!coder || !ov)
488 return NULL;
489 if (ov->spovartyp != SPOVAR_VARIABLE)
490 return ov;
491 tmp = coder->frame->variables;
492 while (tmp) {
493 if (!strcmp(tmp->name, OV_s(ov))) {
494 if ((tmp->svtyp & SPOVAR_ARRAY)) {
495 array_idx = opvar_var_conversion(coder,
496 splev_stack_pop(coder->stack));
497 if (!array_idx || OV_typ(array_idx) != SPOVAR_INT)
498 panic("array idx not an int");
499 if (tmp->array_len < 1)
500 panic("array len < 1");
501 OV_i(array_idx) = (OV_i(array_idx) % tmp->array_len);
502 tmpov = opvar_clone(tmp->data.arrayvalues[OV_i(array_idx)]);
503 opvar_free(array_idx);
504 return tmpov;
505 } else {
506 tmpov = opvar_clone(tmp->data.value);
507 return tmpov;
508 }
509 }
510 tmp = tmp->next;
511 }
512 return NULL;
513 }
514
515 struct splev_var *
opvar_var_defined(coder,name)516 opvar_var_defined(coder, name)
517 struct sp_coder *coder;
518 char *name;
519 {
520 struct splev_var *tmp;
521
522 if (!coder)
523 return NULL;
524 tmp = coder->frame->variables;
525 while (tmp) {
526 if (!strcmp(tmp->name, name))
527 return tmp;
528 tmp = tmp->next;
529 }
530 return NULL;
531 }
532
533 struct opvar *
splev_stack_getdat(coder,typ)534 splev_stack_getdat(coder, typ)
535 struct sp_coder *coder;
536 xchar typ;
537 {
538 static const char nhFunc[] = "splev_stack_getdat";
539 if (coder && coder->stack) {
540 struct opvar *tmp = splev_stack_pop(coder->stack);
541 struct opvar *ret = NULL;
542
543 if (!tmp)
544 panic("no value type %i in stack.", typ);
545 if (tmp->spovartyp == SPOVAR_VARIABLE) {
546 ret = opvar_var_conversion(coder, tmp);
547 opvar_free(tmp);
548 tmp = ret;
549 }
550 if (tmp->spovartyp == typ)
551 return tmp;
552 else opvar_free(tmp);
553 }
554 return NULL;
555 }
556
557 struct opvar *
splev_stack_getdat_any(coder)558 splev_stack_getdat_any(coder)
559 struct sp_coder *coder;
560 {
561 static const char nhFunc[] = "splev_stack_getdat_any";
562 if (coder && coder->stack) {
563 struct opvar *tmp = splev_stack_pop(coder->stack);
564 if (tmp && tmp->spovartyp == SPOVAR_VARIABLE) {
565 struct opvar *ret = opvar_var_conversion(coder, tmp);
566 opvar_free(tmp);
567 return ret;
568 }
569 return tmp;
570 }
571 return NULL;
572 }
573
574 void
variable_list_del(varlist)575 variable_list_del(varlist)
576 struct splev_var *varlist;
577 {
578 static const char nhFunc[] = "variable_list_del";
579 struct splev_var *tmp = varlist;
580
581 if (!tmp)
582 return;
583 while (tmp) {
584 Free(tmp->name);
585 if ((tmp->svtyp & SPOVAR_ARRAY)) {
586 long idx = tmp->array_len;
587
588 while (idx-- > 0) {
589 opvar_free(tmp->data.arrayvalues[idx]);
590 };
591 Free(tmp->data.arrayvalues);
592 } else {
593 opvar_free(tmp->data.value);
594 }
595 tmp = varlist->next;
596 Free(varlist);
597 varlist = tmp;
598 }
599 }
600
601 void
lvlfill_maze_grid(x1,y1,x2,y2,filling)602 lvlfill_maze_grid(x1, y1, x2, y2, filling)
603 int x1, y1, x2, y2;
604 schar filling;
605 {
606 int x, y;
607
608 for (x = x1; x <= x2; x++)
609 for (y = y1; y <= y2; y++) {
610 if (level.flags.corrmaze)
611 levl[x][y].typ = STONE;
612 else
613 levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE
614 : filling;
615 }
616 }
617
618 void
lvlfill_solid(filling,lit)619 lvlfill_solid(filling, lit)
620 schar filling;
621 schar lit;
622 {
623 int x, y;
624
625 for (x = 2; x <= x_maze_max; x++)
626 for (y = 0; y <= y_maze_max; y++) {
627 SET_TYPLIT(x, y, filling, lit);
628 }
629 }
630
631 /*
632 * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
633 */
634 STATIC_OVL void
set_wall_property(x1,y1,x2,y2,prop)635 set_wall_property(x1, y1, x2, y2, prop)
636 xchar x1, y1, x2, y2;
637 int prop;
638 {
639 register xchar x, y;
640 struct rm *lev;
641
642 x1 = max(x1, 1);
643 x2 = min(x2, COLNO - 1);
644 y1 = max(y1, 0);
645 y2 = min(y2, ROWNO - 1);
646 for (y = y1; y <= y2; y++)
647 for (x = x1; x <= x2; x++) {
648 lev = &levl[x][y];
649 if (IS_STWALL(lev->typ) || IS_TREE(lev->typ)
650 /* 3.6.2: made iron bars eligible to be flagged nondiggable
651 (checked by chewing(hack.c) and zap_over_floor(zap.c)) */
652 || lev->typ == IRONBARS)
653 lev->wall_info |= prop;
654 }
655 }
656
657 STATIC_OVL void
shuffle_alignments()658 shuffle_alignments()
659 {
660 int i;
661 aligntyp atmp;
662
663 /* shuffle 3 alignments */
664 i = rn2(3);
665 atmp = ralign[2];
666 ralign[2] = ralign[i];
667 ralign[i] = atmp;
668 if (rn2(2)) {
669 atmp = ralign[1];
670 ralign[1] = ralign[0];
671 ralign[0] = atmp;
672 }
673 }
674
675 /*
676 * Count the different features (sinks, fountains) in the level.
677 */
678 STATIC_OVL void
count_features()679 count_features()
680 {
681 xchar x, y;
682
683 level.flags.nfountains = level.flags.nsinks = 0;
684 for (y = 0; y < ROWNO; y++)
685 for (x = 0; x < COLNO; x++) {
686 int typ = levl[x][y].typ;
687 if (typ == FOUNTAIN)
688 level.flags.nfountains++;
689 else if (typ == SINK)
690 level.flags.nsinks++;
691 }
692 }
693
694 void
remove_boundary_syms()695 remove_boundary_syms()
696 {
697 /*
698 * If any CROSSWALLs are found, must change to ROOM after REGION's
699 * are laid out. CROSSWALLS are used to specify "invisible"
700 * boundaries where DOOR syms look bad or aren't desirable.
701 */
702 xchar x, y;
703 boolean has_bounds = FALSE;
704
705 for (x = 0; x < COLNO - 1; x++)
706 for (y = 0; y < ROWNO - 1; y++)
707 if (levl[x][y].typ == CROSSWALL) {
708 has_bounds = TRUE;
709 break;
710 }
711 if (has_bounds) {
712 for (x = 0; x < x_maze_max; x++)
713 for (y = 0; y < y_maze_max; y++)
714 if ((levl[x][y].typ == CROSSWALL) && SpLev_Map[x][y])
715 levl[x][y].typ = ROOM;
716 }
717 }
718
719 /* used by sel_set_door() and link_doors_rooms() */
720 STATIC_OVL void
set_door_orientation(x,y)721 set_door_orientation(x, y)
722 int x, y;
723 {
724 boolean wleft, wright, wup, wdown;
725
726 /* If there's a wall or door on either the left side or right
727 * side (or both) of this secret door, make it be horizontal.
728 *
729 * It is feasible to put SDOOR in a corner, tee, or crosswall
730 * position, although once the door is found and opened it won't
731 * make a lot sense (diagonal access required). Still, we try to
732 * handle that as best as possible. For top or bottom tee, using
733 * horizontal is the best we can do. For corner or crosswall,
734 * either horizontal or vertical are just as good as each other;
735 * we produce horizontal for corners and vertical for crosswalls.
736 * For left or right tee, using vertical is best.
737 *
738 * A secret door with no adjacent walls is also feasible and makes
739 * even less sense. It will be displayed as a vertical wall while
740 * hidden and become a vertical door when found. Before resorting
741 * to that, we check for solid rock which hasn't been wallified
742 * yet (cf lower leftside of leader's room in Cav quest).
743 */
744 wleft = (isok(x - 1, y) && (IS_WALL(levl[x - 1][y].typ)
745 || IS_DOOR(levl[x - 1][y].typ)
746 || levl[x - 1][y].typ == SDOOR));
747 wright = (isok(x + 1, y) && (IS_WALL(levl[x + 1][y].typ)
748 || IS_DOOR(levl[x + 1][y].typ)
749 || levl[x + 1][y].typ == SDOOR));
750 wup = (isok(x, y - 1) && (IS_WALL(levl[x][y - 1].typ)
751 || IS_DOOR(levl[x][y - 1].typ)
752 || levl[x][y - 1].typ == SDOOR));
753 wdown = (isok(x, y + 1) && (IS_WALL(levl[x][y + 1].typ)
754 || IS_DOOR(levl[x][y + 1].typ)
755 || levl[x][y + 1].typ == SDOOR));
756 if (!wleft && !wright && !wup && !wdown) {
757 /* out of bounds is treated as implicit wall; should be academic
758 because we don't expect to have doors so near the level's edge */
759 wleft = (!isok(x - 1, y) || IS_DOORJOIN(levl[x - 1][y].typ));
760 wright = (!isok(x + 1, y) || IS_DOORJOIN(levl[x + 1][y].typ));
761 wup = (!isok(x, y - 1) || IS_DOORJOIN(levl[x][y - 1].typ));
762 wdown = (!isok(x, y + 1) || IS_DOORJOIN(levl[x][y + 1].typ));
763 }
764 levl[x][y].horizontal = ((wleft || wright) && !(wup && wdown)) ? 1 : 0;
765 }
766
767 STATIC_OVL void
maybe_add_door(x,y,droom)768 maybe_add_door(x, y, droom)
769 int x, y;
770 struct mkroom *droom;
771 {
772 if (droom->hx >= 0 && doorindex < DOORMAX && inside_room(droom, x, y))
773 add_door(x, y, droom);
774 }
775
776 STATIC_OVL void
link_doors_rooms()777 link_doors_rooms()
778 {
779 int x, y;
780 int tmpi, m;
781
782 for (y = 0; y < ROWNO; y++)
783 for (x = 0; x < COLNO; x++)
784 if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) {
785 /* in case this door was a '+' or 'S' from the
786 MAP...ENDMAP section without an explicit DOOR
787 directive, set/clear levl[][].horizontal for it */
788 set_door_orientation(x, y);
789
790 for (tmpi = 0; tmpi < nroom; tmpi++) {
791 maybe_add_door(x, y, &rooms[tmpi]);
792 for (m = 0; m < rooms[tmpi].nsubrooms; m++) {
793 maybe_add_door(x, y, rooms[tmpi].sbrooms[m]);
794 }
795 }
796 }
797 }
798
799 void
fill_rooms()800 fill_rooms()
801 {
802 int tmpi, m;
803
804 for (tmpi = 0; tmpi < nroom; tmpi++) {
805 if (rooms[tmpi].needfill)
806 fill_room(&rooms[tmpi], (rooms[tmpi].needfill == 2));
807 for (m = 0; m < rooms[tmpi].nsubrooms; m++)
808 if (rooms[tmpi].sbrooms[m]->needfill)
809 fill_room(rooms[tmpi].sbrooms[m], FALSE);
810 }
811 }
812
813 /*
814 * Choose randomly the state (nodoor, open, closed or locked) for a door
815 */
816 STATIC_OVL int
rnddoor()817 rnddoor()
818 {
819 int i = 1 << rn2(5);
820
821 i >>= 1;
822 return i;
823 }
824
825 /*
826 * Select a random trap
827 */
828 STATIC_OVL int
rndtrap()829 rndtrap()
830 {
831 int rtrap;
832
833 do {
834 rtrap = rnd(TRAPNUM - 1);
835 switch (rtrap) {
836 case HOLE: /* no random holes on special levels */
837 case VIBRATING_SQUARE:
838 case MAGIC_PORTAL:
839 rtrap = NO_TRAP;
840 break;
841 case TRAPDOOR:
842 if (!Can_dig_down(&u.uz))
843 rtrap = NO_TRAP;
844 break;
845 case LEVEL_TELEP:
846 case TELEP_TRAP:
847 if (level.flags.noteleport)
848 rtrap = NO_TRAP;
849 break;
850 case ROLLING_BOULDER_TRAP:
851 case ROCKTRAP:
852 if (In_endgame(&u.uz))
853 rtrap = NO_TRAP;
854 break;
855 }
856 } while (rtrap == NO_TRAP);
857 return rtrap;
858 }
859
860 /*
861 * Coordinates in special level files are handled specially:
862 *
863 * if x or y is < 0, we generate a random coordinate.
864 * The "humidity" flag is used to insure that engravings aren't
865 * created underwater, or eels on dry land.
866 */
867 STATIC_OVL void
get_location(x,y,humidity,croom)868 get_location(x, y, humidity, croom)
869 schar *x, *y;
870 int humidity;
871 struct mkroom *croom;
872 {
873 int cpt = 0;
874 int mx, my, sx, sy;
875
876 if (croom) {
877 mx = croom->lx;
878 my = croom->ly;
879 sx = croom->hx - mx + 1;
880 sy = croom->hy - my + 1;
881 } else {
882 mx = xstart;
883 my = ystart;
884 sx = xsize;
885 sy = ysize;
886 }
887
888 if (*x >= 0) { /* normal locations */
889 *x += mx;
890 *y += my;
891 } else { /* random location */
892 do {
893 if (croom) { /* handle irregular areas */
894 coord tmpc;
895 somexy(croom, &tmpc);
896 *x = tmpc.x;
897 *y = tmpc.y;
898 } else {
899 *x = mx + rn2((int) sx);
900 *y = my + rn2((int) sy);
901 }
902 if (is_ok_location(*x, *y, humidity))
903 break;
904 } while (++cpt < 100);
905 if (cpt >= 100) {
906 register int xx, yy;
907
908 /* last try */
909 for (xx = 0; xx < sx; xx++)
910 for (yy = 0; yy < sy; yy++) {
911 *x = mx + xx;
912 *y = my + yy;
913 if (is_ok_location(*x, *y, humidity))
914 goto found_it;
915 }
916 if (!(humidity & NO_LOC_WARN)) {
917 impossible("get_location: can't find a place!");
918 } else {
919 *x = *y = -1;
920 }
921 }
922 }
923 found_it:
924 ;
925
926 if (!(humidity & ANY_LOC) && !isok(*x, *y)) {
927 if (!(humidity & NO_LOC_WARN)) {
928 /*warning("get_location: (%d,%d) out of bounds", *x, *y);*/
929 *x = x_maze_max;
930 *y = y_maze_max;
931 } else {
932 *x = *y = -1;
933 }
934 }
935 }
936
937 STATIC_OVL boolean
is_ok_location(x,y,humidity)938 is_ok_location(x, y, humidity)
939 register schar x, y;
940 register int humidity;
941 {
942 register int typ;
943
944 if (Is_waterlevel(&u.uz))
945 return TRUE; /* accept any spot */
946
947 /* TODO: Should perhaps check if wall is diggable/passwall? */
948 if (humidity & ANY_LOC)
949 return TRUE;
950
951 if ((humidity & SOLID) && IS_ROCK(levl[x][y].typ))
952 return TRUE;
953
954 if (humidity & DRY) {
955 typ = levl[x][y].typ;
956 if (typ == ROOM || typ == AIR || typ == CLOUD || typ == ICE
957 || typ == CORR)
958 return TRUE;
959 }
960 if ((humidity & SPACELOC) && SPACE_POS(levl[x][y].typ))
961 return TRUE;
962 if ((humidity & WET) && is_pool(x, y))
963 return TRUE;
964 if ((humidity & HOT) && is_lava(x, y))
965 return TRUE;
966 return FALSE;
967 }
968
969 unpacked_coord
get_unpacked_coord(loc,defhumidity)970 get_unpacked_coord(loc, defhumidity)
971 long loc;
972 int defhumidity;
973 {
974 static unpacked_coord c;
975
976 if (loc & SP_COORD_IS_RANDOM) {
977 c.x = c.y = -1;
978 c.is_random = 1;
979 c.getloc_flags = (loc & ~SP_COORD_IS_RANDOM);
980 if (!c.getloc_flags)
981 c.getloc_flags = defhumidity;
982 } else {
983 c.is_random = 0;
984 c.getloc_flags = defhumidity;
985 c.x = SP_COORD_X(loc);
986 c.y = SP_COORD_Y(loc);
987 }
988 return c;
989 }
990
991 STATIC_OVL void
get_location_coord(x,y,humidity,croom,crd)992 get_location_coord(x, y, humidity, croom, crd)
993 schar *x, *y;
994 int humidity;
995 struct mkroom *croom;
996 long crd;
997 {
998 unpacked_coord c;
999
1000 c = get_unpacked_coord(crd, humidity);
1001 *x = c.x;
1002 *y = c.y;
1003 get_location(x, y, c.getloc_flags | (c.is_random ? NO_LOC_WARN : 0),
1004 croom);
1005 if (*x == -1 && *y == -1 && c.is_random)
1006 get_location(x, y, humidity, croom);
1007 }
1008
1009 /*
1010 * Get a relative position inside a room.
1011 * negative values for x or y means RANDOM!
1012 */
1013
1014 STATIC_OVL void
get_room_loc(x,y,croom)1015 get_room_loc(x, y, croom)
1016 schar *x, *y;
1017 struct mkroom *croom;
1018 {
1019 coord c;
1020
1021 if (*x < 0 && *y < 0) {
1022 if (somexy(croom, &c)) {
1023 *x = c.x;
1024 *y = c.y;
1025 } else
1026 panic("get_room_loc : can't find a place!");
1027 } else {
1028 if (*x < 0)
1029 *x = rn2(croom->hx - croom->lx + 1);
1030 if (*y < 0)
1031 *y = rn2(croom->hy - croom->ly + 1);
1032 *x += croom->lx;
1033 *y += croom->ly;
1034 }
1035 }
1036
1037 /*
1038 * Get a relative position inside a room.
1039 * negative values for x or y means RANDOM!
1040 */
1041 STATIC_OVL void
get_free_room_loc(x,y,croom,pos)1042 get_free_room_loc(x, y, croom, pos)
1043 schar *x, *y;
1044 struct mkroom *croom;
1045 packed_coord pos;
1046 {
1047 schar try_x, try_y;
1048 register int trycnt = 0;
1049
1050 get_location_coord(&try_x, &try_y, DRY, croom, pos);
1051 if (levl[try_x][try_y].typ != ROOM) {
1052 do {
1053 try_x = *x, try_y = *y;
1054 get_room_loc(&try_x, &try_y, croom);
1055 } while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100);
1056
1057 if (trycnt > 100)
1058 panic("get_free_room_loc: can't find a place!");
1059 }
1060 *x = try_x, *y = try_y;
1061 }
1062
1063 boolean
check_room(lowx,ddx,lowy,ddy,vault)1064 check_room(lowx, ddx, lowy, ddy, vault)
1065 xchar *lowx, *ddx, *lowy, *ddy;
1066 boolean vault;
1067 {
1068 register int x, y, hix = *lowx + *ddx, hiy = *lowy + *ddy;
1069 register struct rm *lev;
1070 int xlim, ylim, ymax;
1071
1072 xlim = XLIM + (vault ? 1 : 0);
1073 ylim = YLIM + (vault ? 1 : 0);
1074
1075 if (*lowx < 3)
1076 *lowx = 3;
1077 if (*lowy < 2)
1078 *lowy = 2;
1079 if (hix > COLNO - 3)
1080 hix = COLNO - 3;
1081 if (hiy > ROWNO - 3)
1082 hiy = ROWNO - 3;
1083 chk:
1084 if (hix <= *lowx || hiy <= *lowy)
1085 return FALSE;
1086
1087 /* check area around room (and make room smaller if necessary) */
1088 for (x = *lowx - xlim; x <= hix + xlim; x++) {
1089 if (x <= 0 || x >= COLNO)
1090 continue;
1091 y = *lowy - ylim;
1092 ymax = hiy + ylim;
1093 if (y < 0)
1094 y = 0;
1095 if (ymax >= ROWNO)
1096 ymax = (ROWNO - 1);
1097 lev = &levl[x][y];
1098 for (; y <= ymax; y++) {
1099 if (lev++->typ) {
1100 if (!vault) {
1101 debugpline2("strange area [%d,%d] in check_room.", x, y);
1102 }
1103 if (!rn2(3))
1104 return FALSE;
1105 if (x < *lowx)
1106 *lowx = x + xlim + 1;
1107 else
1108 hix = x - xlim - 1;
1109 if (y < *lowy)
1110 *lowy = y + ylim + 1;
1111 else
1112 hiy = y - ylim - 1;
1113 goto chk;
1114 }
1115 }
1116 }
1117 *ddx = hix - *lowx;
1118 *ddy = hiy - *lowy;
1119 return TRUE;
1120 }
1121
1122 /*
1123 * Create a new room.
1124 * This is still very incomplete...
1125 */
1126 boolean
create_room(x,y,w,h,xal,yal,rtype,rlit)1127 create_room(x, y, w, h, xal, yal, rtype, rlit)
1128 xchar x, y;
1129 xchar w, h;
1130 xchar xal, yal;
1131 xchar rtype, rlit;
1132 {
1133 xchar xabs = 0, yabs = 0;
1134 int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp;
1135 NhRect *r1 = 0, r2;
1136 int trycnt = 0;
1137 boolean vault = FALSE;
1138 int xlim = XLIM, ylim = YLIM;
1139
1140 if (rtype == -1) /* Is the type random ? */
1141 rtype = OROOM;
1142
1143 if (rtype == VAULT) {
1144 vault = TRUE;
1145 xlim++;
1146 ylim++;
1147 }
1148
1149 /* on low levels the room is lit (usually) */
1150 /* some other rooms may require lighting */
1151
1152 /* is light state random ? */
1153 if (rlit == -1)
1154 rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
1155
1156 /*
1157 * Here we will try to create a room. If some parameters are
1158 * random we are willing to make several try before we give
1159 * it up.
1160 */
1161 do {
1162 xchar xborder, yborder;
1163 wtmp = w;
1164 htmp = h;
1165 xtmp = x;
1166 ytmp = y;
1167 xaltmp = xal;
1168 yaltmp = yal;
1169
1170 /* First case : a totally random room */
1171
1172 if ((xtmp < 0 && ytmp < 0 && wtmp < 0 && xaltmp < 0 && yaltmp < 0)
1173 || vault) {
1174 xchar hx, hy, lx, ly, dx, dy;
1175 r1 = rnd_rect(); /* Get a random rectangle */
1176
1177 if (!r1) { /* No more free rectangles ! */
1178 debugpline0("No more rects...");
1179 return FALSE;
1180 }
1181 hx = r1->hx;
1182 hy = r1->hy;
1183 lx = r1->lx;
1184 ly = r1->ly;
1185 if (vault)
1186 dx = dy = 1;
1187 else {
1188 dx = 2 + rn2((hx - lx > 28) ? 12 : 8);
1189 dy = 2 + rn2(4);
1190 if (dx * dy > 50)
1191 dy = 50 / dx;
1192 }
1193 xborder = (lx > 0 && hx < COLNO - 1) ? 2 * xlim : xlim + 1;
1194 yborder = (ly > 0 && hy < ROWNO - 1) ? 2 * ylim : ylim + 1;
1195 if (hx - lx < dx + 3 + xborder || hy - ly < dy + 3 + yborder) {
1196 r1 = 0;
1197 continue;
1198 }
1199 xabs = lx + (lx > 0 ? xlim : 3)
1200 + rn2(hx - (lx > 0 ? lx : 3) - dx - xborder + 1);
1201 yabs = ly + (ly > 0 ? ylim : 2)
1202 + rn2(hy - (ly > 0 ? ly : 2) - dy - yborder + 1);
1203 if (ly == 0 && hy >= (ROWNO - 1) && (!nroom || !rn2(nroom))
1204 && (yabs + dy > ROWNO / 2)) {
1205 yabs = rn1(3, 2);
1206 if (nroom < 4 && dy > 1)
1207 dy--;
1208 }
1209 if (!check_room(&xabs, &dx, &yabs, &dy, vault)) {
1210 r1 = 0;
1211 continue;
1212 }
1213 wtmp = dx + 1;
1214 htmp = dy + 1;
1215 r2.lx = xabs - 1;
1216 r2.ly = yabs - 1;
1217 r2.hx = xabs + wtmp;
1218 r2.hy = yabs + htmp;
1219 } else { /* Only some parameters are random */
1220 int rndpos = 0;
1221 if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */
1222 xtmp = rnd(5);
1223 ytmp = rnd(5);
1224 rndpos = 1;
1225 }
1226 if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */
1227 wtmp = rn1(15, 3);
1228 htmp = rn1(8, 2);
1229 }
1230 if (xaltmp == -1) /* Horizontal alignment is RANDOM */
1231 xaltmp = rnd(3);
1232 if (yaltmp == -1) /* Vertical alignment is RANDOM */
1233 yaltmp = rnd(3);
1234
1235 /* Try to generate real (absolute) coordinates here! */
1236
1237 xabs = (((xtmp - 1) * COLNO) / 5) + 1;
1238 yabs = (((ytmp - 1) * ROWNO) / 5) + 1;
1239 switch (xaltmp) {
1240 case LEFT:
1241 break;
1242 case RIGHT:
1243 xabs += (COLNO / 5) - wtmp;
1244 break;
1245 case CENTER:
1246 xabs += ((COLNO / 5) - wtmp) / 2;
1247 break;
1248 }
1249 switch (yaltmp) {
1250 case TOP:
1251 break;
1252 case BOTTOM:
1253 yabs += (ROWNO / 5) - htmp;
1254 break;
1255 case CENTER:
1256 yabs += ((ROWNO / 5) - htmp) / 2;
1257 break;
1258 }
1259
1260 if (xabs + wtmp - 1 > COLNO - 2)
1261 xabs = COLNO - wtmp - 3;
1262 if (xabs < 2)
1263 xabs = 2;
1264 if (yabs + htmp - 1 > ROWNO - 2)
1265 yabs = ROWNO - htmp - 3;
1266 if (yabs < 2)
1267 yabs = 2;
1268
1269 /* Try to find a rectangle that fit our room ! */
1270
1271 r2.lx = xabs - 1;
1272 r2.ly = yabs - 1;
1273 r2.hx = xabs + wtmp + rndpos;
1274 r2.hy = yabs + htmp + rndpos;
1275 r1 = get_rect(&r2);
1276 }
1277 } while (++trycnt <= 100 && !r1);
1278 if (!r1) { /* creation of room failed ? */
1279 return FALSE;
1280 }
1281 split_rects(r1, &r2);
1282
1283 if (!vault) {
1284 smeq[nroom] = nroom;
1285 add_room(xabs, yabs, xabs + wtmp - 1, yabs + htmp - 1, rlit, rtype,
1286 FALSE);
1287 } else {
1288 rooms[nroom].lx = xabs;
1289 rooms[nroom].ly = yabs;
1290 }
1291 return TRUE;
1292 }
1293
1294 /*
1295 * Create a subroom in room proom at pos x,y with width w & height h.
1296 * x & y are relative to the parent room.
1297 */
1298 STATIC_OVL boolean
create_subroom(proom,x,y,w,h,rtype,rlit)1299 create_subroom(proom, x, y, w, h, rtype, rlit)
1300 struct mkroom *proom;
1301 xchar x, y;
1302 xchar w, h;
1303 xchar rtype, rlit;
1304 {
1305 xchar width, height;
1306
1307 width = proom->hx - proom->lx + 1;
1308 height = proom->hy - proom->ly + 1;
1309
1310 /* There is a minimum size for the parent room */
1311 if (width < 4 || height < 4)
1312 return FALSE;
1313
1314 /* Check for random position, size, etc... */
1315
1316 if (w == -1)
1317 w = rnd(width - 3);
1318 if (h == -1)
1319 h = rnd(height - 3);
1320 if (x == -1)
1321 x = rnd(width - w - 1) - 1;
1322 if (y == -1)
1323 y = rnd(height - h - 1) - 1;
1324 if (x == 1)
1325 x = 0;
1326 if (y == 1)
1327 y = 0;
1328 if ((x + w + 1) == width)
1329 x++;
1330 if ((y + h + 1) == height)
1331 y++;
1332 if (rtype == -1)
1333 rtype = OROOM;
1334 if (rlit == -1)
1335 rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
1336 add_subroom(proom, proom->lx + x, proom->ly + y, proom->lx + x + w - 1,
1337 proom->ly + y + h - 1, rlit, rtype, FALSE);
1338 return TRUE;
1339 }
1340
1341 /*
1342 * Create a new door in a room.
1343 * It's placed on a wall (north, south, east or west).
1344 */
1345 STATIC_OVL void
create_door(dd,broom)1346 create_door(dd, broom)
1347 room_door *dd;
1348 struct mkroom *broom;
1349 {
1350 int x = 0, y = 0;
1351 int trycnt = 0, wtry = 0;
1352
1353 if (dd->secret == -1)
1354 dd->secret = rn2(2);
1355
1356 if (dd->mask == -1) {
1357 /* is it a locked door, closed, or a doorway? */
1358 if (!dd->secret) {
1359 if (!rn2(3)) {
1360 if (!rn2(5))
1361 dd->mask = D_ISOPEN;
1362 else if (!rn2(6))
1363 dd->mask = D_LOCKED;
1364 else
1365 dd->mask = D_CLOSED;
1366 if (dd->mask != D_ISOPEN && !rn2(25))
1367 dd->mask |= D_TRAPPED;
1368 } else
1369 dd->mask = D_NODOOR;
1370 } else {
1371 if (!rn2(5))
1372 dd->mask = D_LOCKED;
1373 else
1374 dd->mask = D_CLOSED;
1375
1376 if (!rn2(20))
1377 dd->mask |= D_TRAPPED;
1378 }
1379 }
1380
1381 do {
1382 register int dwall, dpos;
1383
1384 dwall = dd->wall;
1385 if (dwall == -1) /* The wall is RANDOM */
1386 dwall = 1 << rn2(4);
1387
1388 dpos = dd->pos;
1389
1390 /* Convert wall and pos into an absolute coordinate! */
1391 wtry = rn2(4);
1392 switch (wtry) {
1393 case 0:
1394 if (!(dwall & W_NORTH))
1395 goto redoloop;
1396 y = broom->ly - 1;
1397 x = broom->lx
1398 + ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos);
1399 if (IS_ROCK(levl[x][y - 1].typ))
1400 goto redoloop;
1401 goto outdirloop;
1402 case 1:
1403 if (!(dwall & W_SOUTH))
1404 goto redoloop;
1405 y = broom->hy + 1;
1406 x = broom->lx
1407 + ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos);
1408 if (IS_ROCK(levl[x][y + 1].typ))
1409 goto redoloop;
1410 goto outdirloop;
1411 case 2:
1412 if (!(dwall & W_WEST))
1413 goto redoloop;
1414 x = broom->lx - 1;
1415 y = broom->ly
1416 + ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos);
1417 if (IS_ROCK(levl[x - 1][y].typ))
1418 goto redoloop;
1419 goto outdirloop;
1420 case 3:
1421 if (!(dwall & W_EAST))
1422 goto redoloop;
1423 x = broom->hx + 1;
1424 y = broom->ly
1425 + ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos);
1426 if (IS_ROCK(levl[x + 1][y].typ))
1427 goto redoloop;
1428 goto outdirloop;
1429 default:
1430 x = y = 0;
1431 panic("create_door: No wall for door!");
1432 goto outdirloop;
1433 }
1434 outdirloop:
1435 if (okdoor(x, y))
1436 break;
1437 redoloop:
1438 ;
1439 } while (++trycnt <= 100);
1440 if (trycnt > 100) {
1441 impossible("create_door: Can't find a proper place!");
1442 return;
1443 }
1444 levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
1445 levl[x][y].doormask = dd->mask;
1446 }
1447
1448 /*
1449 * Create a secret door in croom on any one of the specified walls.
1450 */
1451 void
create_secret_door(croom,walls)1452 create_secret_door(croom, walls)
1453 struct mkroom *croom;
1454 xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
1455 {
1456 xchar sx, sy; /* location of the secret door */
1457 int count;
1458
1459 for (count = 0; count < 100; count++) {
1460 sx = rn1(croom->hx - croom->lx + 1, croom->lx);
1461 sy = rn1(croom->hy - croom->ly + 1, croom->ly);
1462
1463 switch (rn2(4)) {
1464 case 0: /* top */
1465 if (!(walls & W_NORTH))
1466 continue;
1467 sy = croom->ly - 1;
1468 break;
1469 case 1: /* bottom */
1470 if (!(walls & W_SOUTH))
1471 continue;
1472 sy = croom->hy + 1;
1473 break;
1474 case 2: /* left */
1475 if (!(walls & W_EAST))
1476 continue;
1477 sx = croom->lx - 1;
1478 break;
1479 case 3: /* right */
1480 if (!(walls & W_WEST))
1481 continue;
1482 sx = croom->hx + 1;
1483 break;
1484 }
1485
1486 if (okdoor(sx, sy)) {
1487 levl[sx][sy].typ = SDOOR;
1488 levl[sx][sy].doormask = D_CLOSED;
1489 return;
1490 }
1491 }
1492
1493 impossible("couldn't create secret door on any walls 0x%x", walls);
1494 }
1495
1496 /*
1497 * Create a trap in a room.
1498 */
1499 STATIC_OVL void
create_trap(t,croom)1500 create_trap(t, croom)
1501 spltrap *t;
1502 struct mkroom *croom;
1503 {
1504 schar x = -1, y = -1;
1505 coord tm;
1506
1507 if (croom)
1508 get_free_room_loc(&x, &y, croom, t->coord);
1509 else {
1510 int trycnt = 0;
1511 do {
1512 get_location_coord(&x, &y, DRY, croom, t->coord);
1513 } while ((levl[x][y].typ == STAIRS || levl[x][y].typ == LADDER)
1514 && ++trycnt <= 100);
1515 if (trycnt > 100)
1516 return;
1517 }
1518
1519 tm.x = x;
1520 tm.y = y;
1521
1522 mktrap(t->type, 1, (struct mkroom *) 0, &tm);
1523 }
1524
1525 /*
1526 * Create a monster in a room.
1527 */
1528 STATIC_OVL int
noncoalignment(alignment)1529 noncoalignment(alignment)
1530 aligntyp alignment;
1531 {
1532 int k;
1533
1534 k = rn2(2);
1535 if (!alignment)
1536 return (k ? -1 : 1);
1537 return (k ? -alignment : 0);
1538 }
1539
1540 /* attempt to screen out locations where a mimic-as-boulder shouldn't occur */
1541 STATIC_OVL boolean
m_bad_boulder_spot(x,y)1542 m_bad_boulder_spot(x, y)
1543 int x, y;
1544 {
1545 struct rm *lev;
1546
1547 /* avoid trap locations */
1548 if (t_at(x, y))
1549 return TRUE;
1550 /* try to avoid locations which already have a boulder (this won't
1551 actually work; we get called before objects have been placed...) */
1552 if (sobj_at(BOULDER, x, y))
1553 return TRUE;
1554 /* avoid closed doors */
1555 lev = &levl[x][y];
1556 if (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED | D_LOCKED)) != 0)
1557 return TRUE;
1558 /* spot is ok */
1559 return FALSE;
1560 }
1561
1562 STATIC_OVL int
pm_to_humidity(pm)1563 pm_to_humidity(pm)
1564 struct permonst *pm;
1565 {
1566 int loc = DRY;
1567 if (!pm)
1568 return loc;
1569 if (pm->mlet == S_EEL || amphibious(pm) || is_swimmer(pm))
1570 loc = WET;
1571 if (is_flyer(pm) || is_floater(pm))
1572 loc |= (HOT | WET);
1573 if (passes_walls(pm) || noncorporeal(pm))
1574 loc |= SOLID;
1575 if (flaming(pm))
1576 loc |= HOT;
1577 return loc;
1578 }
1579
1580 STATIC_OVL void
create_monster(m,croom)1581 create_monster(m, croom)
1582 monster *m;
1583 struct mkroom *croom;
1584 {
1585 struct monst *mtmp;
1586 schar x, y;
1587 char class;
1588 aligntyp amask;
1589 coord cc;
1590 struct permonst *pm;
1591 unsigned g_mvflags;
1592
1593 if (m->class >= 0)
1594 class = (char) def_char_to_monclass((char) m->class);
1595 else
1596 class = 0;
1597
1598 if (class == MAXMCLASSES)
1599 panic("create_monster: unknown monster class '%c'", m->class);
1600
1601 amask = (m->align == AM_SPLEV_CO)
1602 ? Align2amask(u.ualignbase[A_ORIGINAL])
1603 : (m->align == AM_SPLEV_NONCO)
1604 ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL]))
1605 : (m->align <= -(MAX_REGISTERS + 1))
1606 ? induced_align(80)
1607 : (m->align < 0 ? ralign[-m->align - 1] : m->align);
1608
1609 if (!class)
1610 pm = (struct permonst *) 0;
1611 else if (m->id != NON_PM) {
1612 pm = &mons[m->id];
1613 g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags;
1614 if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT))
1615 return;
1616 else if (g_mvflags & G_GONE) /* genocided or extinct */
1617 pm = (struct permonst *) 0; /* make random monster */
1618 } else {
1619 pm = mkclass(class, G_NOGEN);
1620 /* if we can't get a specific monster type (pm == 0) then the
1621 class has been genocided, so settle for a random monster */
1622 }
1623 if (In_mines(&u.uz) && pm && your_race(pm)
1624 && (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3))
1625 pm = (struct permonst *) 0;
1626
1627 if (pm) {
1628 int loc = pm_to_humidity(pm);
1629 /* If water-liking monster, first try is without DRY */
1630 get_location_coord(&x, &y, loc | NO_LOC_WARN, croom, m->coord);
1631 if (x == -1 && y == -1) {
1632 loc |= DRY;
1633 get_location_coord(&x, &y, loc, croom, m->coord);
1634 }
1635 } else {
1636 get_location_coord(&x, &y, DRY, croom, m->coord);
1637 }
1638
1639 /* try to find a close place if someone else is already there */
1640 if (MON_AT(x, y) && enexto(&cc, x, y, pm))
1641 x = cc.x, y = cc.y;
1642
1643 if (m->align != -(MAX_REGISTERS + 2))
1644 mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful);
1645 else if (PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD)
1646 mtmp = mk_mplayer(pm, x, y, FALSE);
1647 else
1648 mtmp = makemon(pm, x, y, NO_MM_FLAGS);
1649
1650 if (mtmp) {
1651 x = mtmp->mx, y = mtmp->my; /* sanity precaution */
1652 m->x = x, m->y = y;
1653 /* handle specific attributes for some special monsters */
1654 if (m->name.str)
1655 mtmp = christen_monst(mtmp, m->name.str);
1656
1657 /*
1658 * This doesn't complain if an attempt is made to give a
1659 * non-mimic/non-shapechanger an appearance or to give a
1660 * shapechanger a non-monster shape, it just refuses to comply.
1661 */
1662 if (m->appear_as.str
1663 && ((mtmp->data->mlet == S_MIMIC)
1664 /* shapechanger (chameleons, et al, and vampires) */
1665 || (mtmp->cham >= LOW_PM && m->appear == M_AP_MONSTER))
1666 && !Protection_from_shape_changers) {
1667 int i;
1668
1669 switch (m->appear) {
1670 case M_AP_NOTHING:
1671 impossible(
1672 "create_monster: mon has an appearance, \"%s\", but no type",
1673 m->appear_as.str);
1674 break;
1675
1676 case M_AP_FURNITURE:
1677 for (i = 0; i < MAXPCHARS; i++)
1678 if (!strcmp(defsyms[i].explanation, m->appear_as.str))
1679 break;
1680 if (i == MAXPCHARS) {
1681 impossible("create_monster: can't find feature \"%s\"",
1682 m->appear_as.str);
1683 } else {
1684 mtmp->m_ap_type = M_AP_FURNITURE;
1685 mtmp->mappearance = i;
1686 }
1687 break;
1688
1689 case M_AP_OBJECT:
1690 for (i = 0; i < NUM_OBJECTS; i++)
1691 if (OBJ_NAME(objects[i])
1692 && !strcmp(OBJ_NAME(objects[i]), m->appear_as.str))
1693 break;
1694 if (i == NUM_OBJECTS) {
1695 impossible("create_monster: can't find object \"%s\"",
1696 m->appear_as.str);
1697 } else {
1698 mtmp->m_ap_type = M_AP_OBJECT;
1699 mtmp->mappearance = i;
1700 /* try to avoid placing mimic boulder on a trap */
1701 if (i == BOULDER && m->x < 0
1702 && m_bad_boulder_spot(x, y)) {
1703 int retrylimit = 10;
1704
1705 remove_monster(x, y);
1706 do {
1707 x = m->x;
1708 y = m->y;
1709 get_location(&x, &y, DRY, croom);
1710 if (MON_AT(x, y) && enexto(&cc, x, y, pm))
1711 x = cc.x, y = cc.y;
1712 } while (m_bad_boulder_spot(x, y)
1713 && --retrylimit > 0);
1714 place_monster(mtmp, x, y);
1715 /* if we didn't find a good spot
1716 then mimic something else */
1717 if (!retrylimit)
1718 set_mimic_sym(mtmp);
1719 }
1720 }
1721 break;
1722
1723 case M_AP_MONSTER: {
1724 int mndx;
1725
1726 if (!strcmpi(m->appear_as.str, "random"))
1727 mndx = select_newcham_form(mtmp);
1728 else
1729 mndx = name_to_mon(m->appear_as.str);
1730
1731 if (mndx == NON_PM || (is_vampshifter(mtmp)
1732 && !validvamp(mtmp, &mndx, S_HUMAN))) {
1733 impossible("create_monster: invalid %s (\"%s\")",
1734 (mtmp->data->mlet == S_MIMIC)
1735 ? "mimic appearance"
1736 : (mtmp->data == &mons[PM_WIZARD_OF_YENDOR])
1737 ? "Wizard appearance"
1738 : is_vampshifter(mtmp)
1739 ? "vampire shape"
1740 : "chameleon shape",
1741 m->appear_as.str);
1742 } else if (&mons[mndx] == mtmp->data) {
1743 /* explicitly forcing a mimic to appear as itself */
1744 mtmp->m_ap_type = M_AP_NOTHING;
1745 mtmp->mappearance = 0;
1746 } else if (mtmp->data->mlet == S_MIMIC
1747 || mtmp->data == &mons[PM_WIZARD_OF_YENDOR]) {
1748 /* this is ordinarily only used for Wizard clones
1749 and hasn't been exhaustively tested for mimics */
1750 mtmp->m_ap_type = M_AP_MONSTER;
1751 mtmp->mappearance = mndx;
1752 } else { /* chameleon or vampire */
1753 struct permonst *mdat = &mons[mndx];
1754 struct permonst *olddata = mtmp->data;
1755
1756 mgender_from_permonst(mtmp, mdat);
1757 set_mon_data(mtmp, mdat);
1758 if (emits_light(olddata) != emits_light(mtmp->data)) {
1759 /* used to give light, now doesn't, or vice versa,
1760 or light's range has changed */
1761 if (emits_light(olddata))
1762 del_light_source(LS_MONSTER, (genericptr_t) mtmp);
1763 if (emits_light(mtmp->data))
1764 new_light_source(mtmp->mx, mtmp->my,
1765 emits_light(mtmp->data),
1766 LS_MONSTER, (genericptr_t) mtmp);
1767 }
1768 if (!mtmp->perminvis || pm_invisible(olddata))
1769 mtmp->perminvis = pm_invisible(mdat);
1770 }
1771 break;
1772 }
1773 default:
1774 impossible(
1775 "create_monster: unimplemented mon appear type [%d,\"%s\"]",
1776 m->appear, m->appear_as.str);
1777 break;
1778 }
1779 if (does_block(x, y, &levl[x][y]))
1780 block_point(x, y);
1781 }
1782
1783 if (m->peaceful >= 0) {
1784 mtmp->mpeaceful = m->peaceful;
1785 /* changed mpeaceful again; have to reset malign */
1786 set_malign(mtmp);
1787 }
1788 if (m->asleep >= 0) {
1789 #ifdef UNIXPC
1790 /* optimizer bug strikes again */
1791 if (m->asleep)
1792 mtmp->msleeping = 1;
1793 else
1794 mtmp->msleeping = 0;
1795 #else
1796 mtmp->msleeping = m->asleep;
1797 #endif
1798 }
1799 if (m->seentraps)
1800 mtmp->mtrapseen = m->seentraps;
1801 if (m->female)
1802 mtmp->female = 1;
1803 if (m->cancelled)
1804 mtmp->mcan = 1;
1805 if (m->revived)
1806 mtmp->mrevived = 1;
1807 if (m->avenge)
1808 mtmp->mavenge = 1;
1809 if (m->stunned)
1810 mtmp->mstun = 1;
1811 if (m->confused)
1812 mtmp->mconf = 1;
1813 if (m->invis) {
1814 mtmp->minvis = mtmp->perminvis = 1;
1815 }
1816 if (m->blinded) {
1817 mtmp->mcansee = 0;
1818 mtmp->mblinded = (m->blinded % 127);
1819 }
1820 if (m->paralyzed) {
1821 mtmp->mcanmove = 0;
1822 mtmp->mfrozen = (m->paralyzed % 127);
1823 }
1824 if (m->fleeing) {
1825 mtmp->mflee = 1;
1826 mtmp->mfleetim = (m->fleeing % 127);
1827 }
1828
1829 if (m->has_invent) {
1830 discard_minvent(mtmp);
1831 invent_carrying_monster = mtmp;
1832 }
1833 }
1834 }
1835
1836 /*
1837 * Create an object in a room.
1838 */
1839 STATIC_OVL void
create_object(o,croom)1840 create_object(o, croom)
1841 object *o;
1842 struct mkroom *croom;
1843 {
1844 struct obj *otmp;
1845 schar x, y;
1846 char c;
1847 boolean named; /* has a name been supplied in level description? */
1848
1849 named = o->name.str ? TRUE : FALSE;
1850
1851 get_location_coord(&x, &y, DRY, croom, o->coord);
1852
1853 if (o->class >= 0)
1854 c = o->class;
1855 else
1856 c = 0;
1857
1858 if (!c)
1859 otmp = mkobj_at(RANDOM_CLASS, x, y, !named);
1860 else if (o->id != -1)
1861 otmp = mksobj_at(o->id, x, y, TRUE, !named);
1862 else {
1863 /*
1864 * The special levels are compiled with the default "text" object
1865 * class characters. We must convert them to the internal format.
1866 */
1867 char oclass = (char) def_char_to_objclass(c);
1868
1869 if (oclass == MAXOCLASSES)
1870 panic("create_object: unexpected object class '%c'", c);
1871
1872 /* KMH -- Create piles of gold properly */
1873 if (oclass == COIN_CLASS)
1874 otmp = mkgold(0L, x, y);
1875 else
1876 otmp = mkobj_at(oclass, x, y, !named);
1877 }
1878
1879 if (o->spe != -127) /* That means NOT RANDOM! */
1880 otmp->spe = (schar) o->spe;
1881
1882 switch (o->curse_state) {
1883 case 1:
1884 bless(otmp);
1885 break; /* BLESSED */
1886 case 2:
1887 unbless(otmp);
1888 uncurse(otmp);
1889 break; /* uncursed */
1890 case 3:
1891 curse(otmp);
1892 break; /* CURSED */
1893 default:
1894 break; /* Otherwise it's random and we're happy
1895 * with what mkobj gave us! */
1896 }
1897
1898 /* corpsenm is "empty" if -1, random if -2, otherwise specific */
1899 if (o->corpsenm != NON_PM) {
1900 if (o->corpsenm == NON_PM - 1)
1901 set_corpsenm(otmp, rndmonnum());
1902 else
1903 set_corpsenm(otmp, o->corpsenm);
1904 }
1905 /* set_corpsenm() took care of egg hatch and corpse timers */
1906
1907 if (named)
1908 otmp = oname(otmp, o->name.str);
1909
1910 if (o->eroded) {
1911 if (o->eroded < 0) {
1912 otmp->oerodeproof = 1;
1913 } else {
1914 otmp->oeroded = (o->eroded % 4);
1915 otmp->oeroded2 = ((o->eroded >> 2) % 4);
1916 }
1917 }
1918 if (o->recharged)
1919 otmp->recharged = (o->recharged % 8);
1920 if (o->locked) {
1921 otmp->olocked = 1;
1922 } else if (o->broken) {
1923 otmp->obroken = 1;
1924 otmp->olocked = 0; /* obj generation may set */
1925 }
1926 if (o->trapped == 0 || o->trapped == 1)
1927 otmp->otrapped = o->trapped;
1928 if (o->greased)
1929 otmp->greased = 1;
1930 #ifdef INVISIBLE_OBJECTS
1931 if (o->invis)
1932 otmp->oinvis = 1;
1933 #endif
1934
1935 if (o->quan > 0 && objects[otmp->otyp].oc_merge) {
1936 otmp->quan = o->quan;
1937 otmp->owt = weight(otmp);
1938 }
1939
1940 /* contents (of a container or monster's inventory) */
1941 if (o->containment & SP_OBJ_CONTENT) {
1942 if (!container_idx) {
1943 if (!invent_carrying_monster) {
1944 /*impossible("create_object: no container");*/
1945 /* don't complain, the monster may be gone legally
1946 (eg. unique demon already generated)
1947 TODO: In the case of unique demon lords, they should
1948 get their inventories even when they get generated
1949 outside the des-file. Maybe another data file that
1950 determines what inventories monsters get by default?
1951 */
1952 ; /* ['otmp' remains on floor] */
1953 } else {
1954 remove_object(otmp);
1955 (void) mpickobj(invent_carrying_monster, otmp);
1956 }
1957 } else {
1958 struct obj *cobj = container_obj[container_idx - 1];
1959
1960 remove_object(otmp);
1961 if (cobj) {
1962 (void) add_to_container(cobj, otmp);
1963 cobj->owt = weight(cobj);
1964 } else {
1965 obj_extract_self(otmp);
1966 obfree(otmp, NULL);
1967 return;
1968 }
1969 }
1970 }
1971 /* container */
1972 if (o->containment & SP_OBJ_CONTAINER) {
1973 delete_contents(otmp);
1974 if (container_idx < MAX_CONTAINMENT) {
1975 container_obj[container_idx] = otmp;
1976 container_idx++;
1977 } else
1978 impossible("create_object: too deeply nested containers.");
1979 }
1980
1981 /* Medusa level special case: statues are petrified monsters, so they
1982 * are not stone-resistant and have monster inventory. They also lack
1983 * other contents, but that can be specified as an empty container.
1984 */
1985 if (o->id == STATUE && Is_medusa_level(&u.uz) && o->corpsenm == NON_PM) {
1986 struct monst *was = NULL;
1987 struct obj *obj;
1988 int wastyp;
1989 int i = 0; /* prevent endless loop in case makemon always fails */
1990
1991 /* Named random statues are of player types, and aren't stone-
1992 * resistant (if they were, we'd have to reset the name as well as
1993 * setting corpsenm).
1994 */
1995 for (wastyp = otmp->corpsenm; i < 1000; i++, wastyp = rndmonnum()) {
1996 /* makemon without rndmonst() might create a group */
1997 was = makemon(&mons[wastyp], 0, 0, MM_NOCOUNTBIRTH);
1998 if (was) {
1999 if (!resists_ston(was)) {
2000 (void) propagate(wastyp, TRUE, FALSE);
2001 break;
2002 }
2003 mongone(was);
2004 was = NULL;
2005 }
2006 }
2007 if (was) {
2008 set_corpsenm(otmp, wastyp);
2009 while (was->minvent) {
2010 obj = was->minvent;
2011 obj->owornmask = 0;
2012 obj_extract_self(obj);
2013 (void) add_to_container(otmp, obj);
2014 }
2015 otmp->owt = weight(otmp);
2016 mongone(was);
2017 }
2018 }
2019
2020 if (o->id != -1) {
2021 static const char prize_warning[] = "multiple prizes on %s level";
2022
2023 /* if this is a specific item of the right type and it is being
2024 created on the right level, flag it as the designated item
2025 used to detect a special achievement (to whit, reaching and
2026 exploring the target level, although the exploration part
2027 might be short-circuited if a monster brings object to hero) */
2028 if (Is_mineend_level(&u.uz)) {
2029 if (otmp->otyp == iflags.mines_prize_type) {
2030 if (!mines_prize_count++) {
2031 /* Note: the first luckstone on lev will become the prize
2032 even if its not the explicit one, but random */
2033 otmp->record_achieve_special = MINES_PRIZE;
2034 /* prevent stacking; cleared when achievement is recorded */
2035 otmp->nomerge = 1;
2036 }
2037 }
2038 } else if (Is_sokoend_level(&u.uz)) {
2039 if (otmp->otyp == iflags.soko_prize_type1) {
2040 otmp->record_achieve_special = SOKO_PRIZE1;
2041 otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack */
2042 if (++soko_prize_count > 1)
2043 impossible(prize_warning, "sokoban end");
2044 } else if (otmp->otyp == iflags.soko_prize_type2) {
2045 otmp->record_achieve_special = SOKO_PRIZE2;
2046 otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack */
2047 if (++soko_prize_count > 1)
2048 impossible(prize_warning, "sokoban end");
2049 }
2050 }
2051 }
2052
2053 stackobj(otmp);
2054
2055 if (o->lit) {
2056 begin_burn(otmp, FALSE);
2057 }
2058
2059 if (o->buried) {
2060 boolean dealloced;
2061
2062 (void) bury_an_obj(otmp, &dealloced);
2063 if (dealloced && container_idx) {
2064 container_obj[container_idx - 1] = NULL;
2065 }
2066 }
2067 }
2068
2069 /*
2070 * Create an altar in a room.
2071 */
2072 STATIC_OVL void
create_altar(a,croom)2073 create_altar(a, croom)
2074 altar *a;
2075 struct mkroom *croom;
2076 {
2077 schar sproom, x = -1, y = -1;
2078 aligntyp amask;
2079 boolean croom_is_temple = TRUE;
2080 int oldtyp;
2081
2082 if (croom) {
2083 get_free_room_loc(&x, &y, croom, a->coord);
2084 if (croom->rtype != TEMPLE)
2085 croom_is_temple = FALSE;
2086 } else {
2087 get_location_coord(&x, &y, DRY, croom, a->coord);
2088 if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
2089 croom = &rooms[sproom - ROOMOFFSET];
2090 else
2091 croom_is_temple = FALSE;
2092 }
2093
2094 /* check for existing features */
2095 oldtyp = levl[x][y].typ;
2096 if (oldtyp == STAIRS || oldtyp == LADDER)
2097 return;
2098
2099 /* Is the alignment random ?
2100 * If so, it's an 80% chance that the altar will be co-aligned.
2101 *
2102 * The alignment is encoded as amask values instead of alignment
2103 * values to avoid conflicting with the rest of the encoding,
2104 * shared by many other parts of the special level code.
2105 */
2106 amask = (a->align == AM_SPLEV_CO)
2107 ? Align2amask(u.ualignbase[A_ORIGINAL])
2108 : (a->align == AM_SPLEV_NONCO)
2109 ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL]))
2110 : (a->align == -(MAX_REGISTERS + 1))
2111 ? induced_align(80)
2112 : (a->align < 0 ? ralign[-a->align - 1] : a->align);
2113
2114 levl[x][y].typ = ALTAR;
2115 levl[x][y].altarmask = amask;
2116
2117 if (a->shrine < 0)
2118 a->shrine = rn2(2); /* handle random case */
2119
2120 if (!croom_is_temple || !a->shrine)
2121 return;
2122
2123 if (a->shrine) { /* Is it a shrine or sanctum? */
2124 priestini(&u.uz, croom, x, y, (a->shrine > 1));
2125 levl[x][y].altarmask |= AM_SHRINE;
2126 level.flags.has_temple = TRUE;
2127 }
2128 }
2129
2130 void
replace_terrain(terr,croom)2131 replace_terrain(terr, croom)
2132 replaceterrain *terr;
2133 struct mkroom *croom;
2134 {
2135 schar x, y, x1, y1, x2, y2;
2136
2137 if (terr->toter >= MAX_TYPE)
2138 return;
2139
2140 x1 = terr->x1;
2141 y1 = terr->y1;
2142 get_location(&x1, &y1, ANY_LOC, croom);
2143
2144 x2 = terr->x2;
2145 y2 = terr->y2;
2146 get_location(&x2, &y2, ANY_LOC, croom);
2147
2148 for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++)
2149 for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++)
2150 if (levl[x][y].typ == terr->fromter && rn2(100) < terr->chance) {
2151 SET_TYPLIT(x, y, terr->toter, terr->tolit);
2152 }
2153 }
2154
2155 /*
2156 * Search for a door in a room on a specified wall.
2157 */
2158 STATIC_OVL boolean
search_door(croom,x,y,wall,cnt)2159 search_door(croom, x, y, wall, cnt)
2160 struct mkroom *croom;
2161 xchar *x, *y;
2162 xchar wall;
2163 int cnt;
2164 {
2165 int dx, dy;
2166 int xx, yy;
2167
2168 switch (wall) {
2169 case W_NORTH:
2170 dy = 0;
2171 dx = 1;
2172 xx = croom->lx;
2173 yy = croom->hy + 1;
2174 break;
2175 case W_SOUTH:
2176 dy = 0;
2177 dx = 1;
2178 xx = croom->lx;
2179 yy = croom->ly - 1;
2180 break;
2181 case W_EAST:
2182 dy = 1;
2183 dx = 0;
2184 xx = croom->hx + 1;
2185 yy = croom->ly;
2186 break;
2187 case W_WEST:
2188 dy = 1;
2189 dx = 0;
2190 xx = croom->lx - 1;
2191 yy = croom->ly;
2192 break;
2193 default:
2194 dx = dy = xx = yy = 0;
2195 panic("search_door: Bad wall!");
2196 break;
2197 }
2198 while (xx <= croom->hx + 1 && yy <= croom->hy + 1) {
2199 if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
2200 *x = xx;
2201 *y = yy;
2202 if (cnt-- <= 0)
2203 return TRUE;
2204 }
2205 xx += dx;
2206 yy += dy;
2207 }
2208 return FALSE;
2209 }
2210
2211 /*
2212 * Dig a corridor between two points.
2213 */
2214 boolean
dig_corridor(org,dest,nxcor,ftyp,btyp)2215 dig_corridor(org, dest, nxcor, ftyp, btyp)
2216 coord *org, *dest;
2217 boolean nxcor;
2218 schar ftyp, btyp;
2219 {
2220 int dx = 0, dy = 0, dix, diy, cct;
2221 struct rm *crm;
2222 int tx, ty, xx, yy;
2223
2224 xx = org->x;
2225 yy = org->y;
2226 tx = dest->x;
2227 ty = dest->y;
2228 if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 || xx > COLNO - 1
2229 || tx > COLNO - 1 || yy > ROWNO - 1 || ty > ROWNO - 1) {
2230 debugpline4("dig_corridor: bad coords <%d,%d> <%d,%d>.",
2231 xx, yy, tx, ty);
2232 return FALSE;
2233 }
2234 if (tx > xx)
2235 dx = 1;
2236 else if (ty > yy)
2237 dy = 1;
2238 else if (tx < xx)
2239 dx = -1;
2240 else
2241 dy = -1;
2242
2243 xx -= dx;
2244 yy -= dy;
2245 cct = 0;
2246 while (xx != tx || yy != ty) {
2247 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
2248 if (cct++ > 500 || (nxcor && !rn2(35)))
2249 return FALSE;
2250
2251 xx += dx;
2252 yy += dy;
2253
2254 if (xx >= COLNO - 1 || xx <= 0 || yy <= 0 || yy >= ROWNO - 1)
2255 return FALSE; /* impossible */
2256
2257 crm = &levl[xx][yy];
2258 if (crm->typ == btyp) {
2259 if (ftyp != CORR || rn2(100)) {
2260 crm->typ = ftyp;
2261 if (nxcor && !rn2(50))
2262 (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
2263 } else {
2264 crm->typ = SCORR;
2265 }
2266 } else if (crm->typ != ftyp && crm->typ != SCORR) {
2267 /* strange ... */
2268 return FALSE;
2269 }
2270
2271 /* find next corridor position */
2272 dix = abs(xx - tx);
2273 diy = abs(yy - ty);
2274
2275 if ((dix > diy) && diy && !rn2(dix-diy+1)) {
2276 dix = 0;
2277 } else if ((diy > dix) && dix && !rn2(diy-dix+1)) {
2278 diy = 0;
2279 }
2280
2281 /* do we have to change direction ? */
2282 if (dy && dix > diy) {
2283 register int ddx = (xx > tx) ? -1 : 1;
2284
2285 crm = &levl[xx + ddx][yy];
2286 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
2287 dx = ddx;
2288 dy = 0;
2289 continue;
2290 }
2291 } else if (dx && diy > dix) {
2292 register int ddy = (yy > ty) ? -1 : 1;
2293
2294 crm = &levl[xx][yy + ddy];
2295 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
2296 dy = ddy;
2297 dx = 0;
2298 continue;
2299 }
2300 }
2301
2302 /* continue straight on? */
2303 crm = &levl[xx + dx][yy + dy];
2304 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
2305 continue;
2306
2307 /* no, what must we do now?? */
2308 if (dx) {
2309 dx = 0;
2310 dy = (ty < yy) ? -1 : 1;
2311 } else {
2312 dy = 0;
2313 dx = (tx < xx) ? -1 : 1;
2314 }
2315 crm = &levl[xx + dx][yy + dy];
2316 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
2317 continue;
2318 dy = -dy;
2319 dx = -dx;
2320 }
2321 return TRUE;
2322 }
2323
2324 /*
2325 * Disgusting hack: since special levels have their rooms filled before
2326 * sorting the rooms, we have to re-arrange the speed values upstairs_room
2327 * and dnstairs_room after the rooms have been sorted. On normal levels,
2328 * stairs don't get created until _after_ sorting takes place.
2329 */
2330 STATIC_OVL void
fix_stair_rooms()2331 fix_stair_rooms()
2332 {
2333 int i;
2334 struct mkroom *croom;
2335
2336 if (xdnstair
2337 && !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx)
2338 && (dnstairs_room->ly <= ydnstair
2339 && ydnstair <= dnstairs_room->hy))) {
2340 for (i = 0; i < nroom; i++) {
2341 croom = &rooms[i];
2342 if ((croom->lx <= xdnstair && xdnstair <= croom->hx)
2343 && (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
2344 dnstairs_room = croom;
2345 break;
2346 }
2347 }
2348 if (i == nroom)
2349 panic("Couldn't find dnstair room in fix_stair_rooms!");
2350 }
2351 if (xupstair
2352 && !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx)
2353 && (upstairs_room->ly <= yupstair
2354 && yupstair <= upstairs_room->hy))) {
2355 for (i = 0; i < nroom; i++) {
2356 croom = &rooms[i];
2357 if ((croom->lx <= xupstair && xupstair <= croom->hx)
2358 && (croom->ly <= yupstair && yupstair <= croom->hy)) {
2359 upstairs_room = croom;
2360 break;
2361 }
2362 }
2363 if (i == nroom)
2364 panic("Couldn't find upstair room in fix_stair_rooms!");
2365 }
2366 }
2367
2368 /*
2369 * Corridors always start from a door. But it can end anywhere...
2370 * Basically we search for door coordinates or for endpoints coordinates
2371 * (from a distance).
2372 */
2373 STATIC_OVL void
create_corridor(c)2374 create_corridor(c)
2375 corridor *c;
2376 {
2377 coord org, dest;
2378
2379 if (c->src.room == -1) {
2380 fix_stair_rooms();
2381 makecorridors(); /*makecorridors(c->src.door);*/
2382 return;
2383 }
2384
2385 if (!search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
2386 c->src.door))
2387 return;
2388
2389 if (c->dest.room != -1) {
2390 if (!search_door(&rooms[c->dest.room], &dest.x, &dest.y, c->dest.wall,
2391 c->dest.door))
2392 return;
2393 switch (c->src.wall) {
2394 case W_NORTH:
2395 org.y--;
2396 break;
2397 case W_SOUTH:
2398 org.y++;
2399 break;
2400 case W_WEST:
2401 org.x--;
2402 break;
2403 case W_EAST:
2404 org.x++;
2405 break;
2406 }
2407 switch (c->dest.wall) {
2408 case W_NORTH:
2409 dest.y--;
2410 break;
2411 case W_SOUTH:
2412 dest.y++;
2413 break;
2414 case W_WEST:
2415 dest.x--;
2416 break;
2417 case W_EAST:
2418 dest.x++;
2419 break;
2420 }
2421 (void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
2422 }
2423 }
2424
2425 /*
2426 * Fill a room (shop, zoo, etc...) with appropriate stuff.
2427 */
2428 void
fill_room(croom,prefilled)2429 fill_room(croom, prefilled)
2430 struct mkroom *croom;
2431 boolean prefilled;
2432 {
2433 if (!croom || croom->rtype == OROOM)
2434 return;
2435
2436 if (!prefilled) {
2437 int x, y;
2438
2439 /* Shop ? */
2440 if (croom->rtype >= SHOPBASE) {
2441 stock_room(croom->rtype - SHOPBASE, croom);
2442 level.flags.has_shop = TRUE;
2443 return;
2444 }
2445
2446 switch (croom->rtype) {
2447 case VAULT:
2448 for (x = croom->lx; x <= croom->hx; x++)
2449 for (y = croom->ly; y <= croom->hy; y++)
2450 (void) mkgold((long) rn1(abs(depth(&u.uz)) * 100, 51),
2451 x, y);
2452 break;
2453 case COURT:
2454 case ZOO:
2455 case BEEHIVE:
2456 case ANTHOLE:
2457 case COCKNEST:
2458 case LEPREHALL:
2459 case MORGUE:
2460 case BARRACKS:
2461 fill_zoo(croom);
2462 break;
2463 }
2464 }
2465 switch (croom->rtype) {
2466 case VAULT:
2467 level.flags.has_vault = TRUE;
2468 break;
2469 case ZOO:
2470 level.flags.has_zoo = TRUE;
2471 break;
2472 case COURT:
2473 level.flags.has_court = TRUE;
2474 break;
2475 case MORGUE:
2476 level.flags.has_morgue = TRUE;
2477 break;
2478 case BEEHIVE:
2479 level.flags.has_beehive = TRUE;
2480 break;
2481 case BARRACKS:
2482 level.flags.has_barracks = TRUE;
2483 break;
2484 case TEMPLE:
2485 level.flags.has_temple = TRUE;
2486 break;
2487 case SWAMP:
2488 level.flags.has_swamp = TRUE;
2489 break;
2490 }
2491 }
2492
2493 struct mkroom *
build_room(r,mkr)2494 build_room(r, mkr)
2495 room *r;
2496 struct mkroom *mkr;
2497 {
2498 boolean okroom;
2499 struct mkroom *aroom;
2500 xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
2501
2502 if (mkr) {
2503 aroom = &subrooms[nsubroom];
2504 okroom = create_subroom(mkr, r->x, r->y, r->w, r->h, rtype, r->rlit);
2505 } else {
2506 aroom = &rooms[nroom];
2507 okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, r->yalign,
2508 rtype, r->rlit);
2509 }
2510
2511 if (okroom) {
2512 #ifdef SPECIALIZATION
2513 topologize(aroom, FALSE); /* set roomno */
2514 #else
2515 topologize(aroom); /* set roomno */
2516 #endif
2517 aroom->needfill = r->filled;
2518 aroom->needjoining = r->joined;
2519 return aroom;
2520 }
2521 return (struct mkroom *) 0;
2522 }
2523
2524 /*
2525 * set lighting in a region that will not become a room.
2526 */
2527 STATIC_OVL void
light_region(tmpregion)2528 light_region(tmpregion)
2529 region *tmpregion;
2530 {
2531 register boolean litstate = tmpregion->rlit ? 1 : 0;
2532 register int hiy = tmpregion->y2;
2533 register int x, y;
2534 register struct rm *lev;
2535 int lowy = tmpregion->y1;
2536 int lowx = tmpregion->x1, hix = tmpregion->x2;
2537
2538 if (litstate) {
2539 /* adjust region size for walls, but only if lighted */
2540 lowx = max(lowx - 1, 1);
2541 hix = min(hix + 1, COLNO - 1);
2542 lowy = max(lowy - 1, 0);
2543 hiy = min(hiy + 1, ROWNO - 1);
2544 }
2545 for (x = lowx; x <= hix; x++) {
2546 lev = &levl[x][lowy];
2547 for (y = lowy; y <= hiy; y++) {
2548 if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
2549 lev->lit = litstate;
2550 lev++;
2551 }
2552 }
2553 }
2554
2555 STATIC_OVL void
wallify_map(x1,y1,x2,y2)2556 wallify_map(x1, y1, x2, y2)
2557 int x1, y1, x2, y2;
2558 {
2559 int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
2560
2561 y1 = max(y1, 0);
2562 x1 = max(x1, 1);
2563 y2 = min(y2, ROWNO - 1);
2564 x2 = min(x2, COLNO - 1);
2565 for (y = y1; y <= y2; y++) {
2566 lo_yy = (y > 0) ? y - 1 : 0;
2567 hi_yy = (y < y2) ? y + 1 : y2;
2568 for (x = x1; x <= x2; x++) {
2569 if (levl[x][y].typ != STONE)
2570 continue;
2571 lo_xx = (x > 1) ? x - 1 : 1;
2572 hi_xx = (x < x2) ? x + 1 : x2;
2573 for (yy = lo_yy; yy <= hi_yy; yy++)
2574 for (xx = lo_xx; xx <= hi_xx; xx++)
2575 if (IS_ROOM(levl[xx][yy].typ)
2576 || levl[xx][yy].typ == CROSSWALL) {
2577 levl[x][y].typ = (yy != y) ? HWALL : VWALL;
2578 yy = hi_yy; /* end `yy' loop */
2579 break; /* end `xx' loop */
2580 }
2581 }
2582 }
2583 }
2584
2585 /*
2586 * Select a random coordinate in the maze.
2587 *
2588 * We want a place not 'touched' by the loader. That is, a place in
2589 * the maze outside every part of the special level.
2590 */
2591 STATIC_OVL void
maze1xy(m,humidity)2592 maze1xy(m, humidity)
2593 coord *m;
2594 int humidity;
2595 {
2596 register int x, y, tryct = 2000;
2597 /* tryct: normally it won't take more than ten or so tries due
2598 to the circumstances under which we'll be called, but the
2599 `humidity' screening might drastically change the chances */
2600
2601 do {
2602 x = rn1(x_maze_max - 3, 3);
2603 y = rn1(y_maze_max - 3, 3);
2604 if (--tryct < 0)
2605 break; /* give up */
2606 } while (!(x % 2) || !(y % 2) || SpLev_Map[x][y]
2607 || !is_ok_location((schar) x, (schar) y, humidity));
2608
2609 m->x = (xchar) x, m->y = (xchar) y;
2610 }
2611
2612 /*
2613 * If there's a significant portion of maze unused by the special level,
2614 * we don't want it empty.
2615 *
2616 * Makes the number of traps, monsters, etc. proportional
2617 * to the size of the maze.
2618 */
2619 STATIC_OVL void
fill_empty_maze()2620 fill_empty_maze()
2621 {
2622 int mapcountmax, mapcount, mapfact;
2623 xchar x, y;
2624 coord mm;
2625
2626 mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2627 mapcountmax = mapcountmax / 2;
2628
2629 for (x = 2; x < x_maze_max; x++)
2630 for (y = 0; y < y_maze_max; y++)
2631 if (SpLev_Map[x][y])
2632 mapcount--;
2633
2634 if ((mapcount > (int) (mapcountmax / 10))) {
2635 mapfact = (int) ((mapcount * 100L) / mapcountmax);
2636 for (x = rnd((int) (20 * mapfact) / 100); x; x--) {
2637 maze1xy(&mm, DRY);
2638 (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS, mm.x, mm.y,
2639 TRUE);
2640 }
2641 for (x = rnd((int) (12 * mapfact) / 100); x; x--) {
2642 maze1xy(&mm, DRY);
2643 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
2644 }
2645 for (x = rn2(2); x; x--) {
2646 maze1xy(&mm, DRY);
2647 (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
2648 }
2649 for (x = rnd((int) (12 * mapfact) / 100); x; x--) {
2650 maze1xy(&mm, DRY);
2651 (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
2652 }
2653 for (x = rn2((int) (15 * mapfact) / 100); x; x--) {
2654 maze1xy(&mm, DRY);
2655 (void) mkgold(0L, mm.x, mm.y);
2656 }
2657 for (x = rn2((int) (15 * mapfact) / 100); x; x--) {
2658 int trytrap;
2659
2660 maze1xy(&mm, DRY);
2661 trytrap = rndtrap();
2662 if (sobj_at(BOULDER, mm.x, mm.y))
2663 while (is_pit(trytrap) || is_hole(trytrap))
2664 trytrap = rndtrap();
2665 (void) maketrap(mm.x, mm.y, trytrap);
2666 }
2667 }
2668 }
2669
2670 /*
2671 * special level loader
2672 */
2673 STATIC_OVL boolean
sp_level_loader(fd,lvl)2674 sp_level_loader(fd, lvl)
2675 dlb *fd;
2676 sp_lev *lvl;
2677 {
2678 long n_opcode = 0;
2679 struct opvar *opdat;
2680 int opcode;
2681
2682 Fread((genericptr_t) & (lvl->n_opcodes), 1, sizeof(lvl->n_opcodes), fd);
2683 lvl->opcodes = (_opcode *) alloc(sizeof(_opcode) * (lvl->n_opcodes));
2684
2685 while (n_opcode < lvl->n_opcodes) {
2686 Fread((genericptr_t) &lvl->opcodes[n_opcode].opcode, 1,
2687 sizeof(lvl->opcodes[n_opcode].opcode), fd);
2688 opcode = lvl->opcodes[n_opcode].opcode;
2689
2690 opdat = NULL;
2691
2692 if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES)
2693 panic("sp_level_loader: impossible opcode %i.", opcode);
2694
2695 if (opcode == SPO_PUSH) {
2696 int nsize;
2697 struct opvar *ov = (struct opvar *) alloc(sizeof(struct opvar));
2698
2699 opdat = ov;
2700 ov->spovartyp = SPO_NULL;
2701 ov->vardata.l = 0;
2702 Fread((genericptr_t) & (ov->spovartyp), 1, sizeof(ov->spovartyp),
2703 fd);
2704
2705 switch (ov->spovartyp) {
2706 case SPOVAR_NULL:
2707 break;
2708 case SPOVAR_COORD:
2709 case SPOVAR_REGION:
2710 case SPOVAR_MAPCHAR:
2711 case SPOVAR_MONST:
2712 case SPOVAR_OBJ:
2713 case SPOVAR_INT:
2714 Fread((genericptr_t) & (ov->vardata.l), 1,
2715 sizeof(ov->vardata.l), fd);
2716 break;
2717 case SPOVAR_VARIABLE:
2718 case SPOVAR_STRING:
2719 case SPOVAR_SEL: {
2720 char *opd;
2721
2722 Fread((genericptr_t) &nsize, 1, sizeof(nsize), fd);
2723 opd = (char *) alloc(nsize + 1);
2724
2725 if (nsize)
2726 Fread(opd, 1, nsize, fd);
2727 opd[nsize] = 0;
2728 ov->vardata.str = opd;
2729 break;
2730 }
2731 default:
2732 panic("sp_level_loader: unknown opvar type %i",
2733 ov->spovartyp);
2734 }
2735 }
2736
2737 lvl->opcodes[n_opcode].opdat = opdat;
2738 n_opcode++;
2739 } /*while*/
2740
2741 return TRUE;
2742 }
2743
2744 /* Frees the memory allocated for special level creation structs */
2745 STATIC_OVL boolean
sp_level_free(lvl)2746 sp_level_free(lvl)
2747 sp_lev *lvl;
2748 {
2749 static const char nhFunc[] = "sp_level_free";
2750 long n_opcode = 0;
2751
2752 while (n_opcode < lvl->n_opcodes) {
2753 int opcode = lvl->opcodes[n_opcode].opcode;
2754 struct opvar *opdat = lvl->opcodes[n_opcode].opdat;
2755
2756 if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES)
2757 panic("sp_level_free: unknown opcode %i", opcode);
2758
2759 if (opdat)
2760 opvar_free(opdat);
2761 n_opcode++;
2762 }
2763 Free(lvl->opcodes);
2764 lvl->opcodes = NULL;
2765 return TRUE;
2766 }
2767
2768 void
splev_initlev(linit)2769 splev_initlev(linit)
2770 lev_init *linit;
2771 {
2772 switch (linit->init_style) {
2773 default:
2774 impossible("Unrecognized level init style.");
2775 break;
2776 case LVLINIT_NONE:
2777 break;
2778 case LVLINIT_SOLIDFILL:
2779 if (linit->lit == -1)
2780 linit->lit = rn2(2);
2781 lvlfill_solid(linit->filling, linit->lit);
2782 break;
2783 case LVLINIT_MAZEGRID:
2784 lvlfill_maze_grid(2, 0, x_maze_max, y_maze_max, linit->filling);
2785 break;
2786 case LVLINIT_ROGUE:
2787 makeroguerooms();
2788 break;
2789 case LVLINIT_MINES:
2790 if (linit->lit == -1)
2791 linit->lit = rn2(2);
2792 if (linit->filling > -1)
2793 lvlfill_solid(linit->filling, 0);
2794 linit->icedpools = icedpools;
2795 mkmap(linit);
2796 break;
2797 }
2798 }
2799
2800 struct sp_frame *
frame_new(execptr)2801 frame_new(execptr)
2802 long execptr;
2803 {
2804 struct sp_frame *frame =
2805 (struct sp_frame *) alloc(sizeof(struct sp_frame));
2806
2807 frame->next = NULL;
2808 frame->variables = NULL;
2809 frame->n_opcode = execptr;
2810 frame->stack = (struct splevstack *) alloc(sizeof(struct splevstack));
2811 splev_stack_init(frame->stack);
2812 return frame;
2813 }
2814
2815 void
frame_del(frame)2816 frame_del(frame)
2817 struct sp_frame *frame;
2818 {
2819 if (!frame)
2820 return;
2821 if (frame->stack) {
2822 splev_stack_done(frame->stack);
2823 frame->stack = NULL;
2824 }
2825 if (frame->variables) {
2826 variable_list_del(frame->variables);
2827 frame->variables = NULL;
2828 }
2829 Free(frame);
2830 }
2831
2832 void
spo_frame_push(coder)2833 spo_frame_push(coder)
2834 struct sp_coder *coder;
2835 {
2836 struct sp_frame *tmpframe = frame_new(coder->frame->n_opcode);
2837
2838 tmpframe->next = coder->frame;
2839 coder->frame = tmpframe;
2840 }
2841
2842 void
spo_frame_pop(coder)2843 spo_frame_pop(coder)
2844 struct sp_coder *coder;
2845 {
2846 if (coder->frame && coder->frame->next) {
2847 struct sp_frame *tmpframe = coder->frame->next;
2848
2849 frame_del(coder->frame);
2850 coder->frame = tmpframe;
2851 coder->stack = coder->frame->stack;
2852 }
2853 }
2854
2855 long
sp_code_jmpaddr(curpos,jmpaddr)2856 sp_code_jmpaddr(curpos, jmpaddr)
2857 long curpos, jmpaddr;
2858 {
2859 return (curpos + jmpaddr);
2860 }
2861
2862 void
spo_call(coder)2863 spo_call(coder)
2864 struct sp_coder *coder;
2865 {
2866 static const char nhFunc[] = "spo_call";
2867 struct opvar *addr;
2868 struct opvar *params;
2869 struct sp_frame *tmpframe;
2870
2871 if (!OV_pop_i(addr) || !OV_pop_i(params))
2872 return;
2873 if (OV_i(params) < 0)
2874 return;
2875
2876 tmpframe = frame_new(sp_code_jmpaddr(coder->frame->n_opcode,
2877 OV_i(addr) - 1));
2878
2879 while (OV_i(params)-- > 0) {
2880 splev_stack_push(tmpframe->stack, splev_stack_getdat_any(coder));
2881 }
2882 splev_stack_reverse(tmpframe->stack);
2883
2884 /* push a frame */
2885 tmpframe->next = coder->frame;
2886 coder->frame = tmpframe;
2887
2888 opvar_free(addr);
2889 opvar_free(params);
2890 }
2891
2892 void
spo_return(coder)2893 spo_return(coder)
2894 struct sp_coder *coder;
2895 {
2896 static const char nhFunc[] = "spo_return";
2897 struct opvar *params;
2898
2899 if (!coder->frame || !coder->frame->next)
2900 panic("return: no frame.");
2901 if (!OV_pop_i(params))
2902 return;
2903 if (OV_i(params) < 0)
2904 return;
2905
2906 while (OV_i(params)-- > 0) {
2907 splev_stack_push(coder->frame->next->stack,
2908 splev_stack_pop(coder->stack));
2909 }
2910
2911 /* pop the frame */
2912 if (coder->frame->next) {
2913 struct sp_frame *tmpframe = coder->frame->next;
2914 frame_del(coder->frame);
2915 coder->frame = tmpframe;
2916 coder->stack = coder->frame->stack;
2917 }
2918
2919 opvar_free(params);
2920 }
2921
2922 /*ARGUSED*/
2923 void
spo_end_moninvent(coder)2924 spo_end_moninvent(coder)
2925 struct sp_coder *coder UNUSED;
2926 {
2927 if (invent_carrying_monster)
2928 m_dowear(invent_carrying_monster, TRUE);
2929 invent_carrying_monster = NULL;
2930 }
2931
2932 /*ARGUSED*/
2933 void
spo_pop_container(coder)2934 spo_pop_container(coder)
2935 struct sp_coder *coder UNUSED;
2936 {
2937 if (container_idx > 0) {
2938 container_idx--;
2939 container_obj[container_idx] = NULL;
2940 }
2941 }
2942
2943 void
spo_message(coder)2944 spo_message(coder)
2945 struct sp_coder *coder;
2946 {
2947 static const char nhFunc[] = "spo_message";
2948 struct opvar *op;
2949 char *msg, *levmsg;
2950 int old_n, n;
2951
2952 if (!OV_pop_s(op))
2953 return;
2954 msg = OV_s(op);
2955 if (!msg)
2956 return;
2957
2958 old_n = lev_message ? (strlen(lev_message) + 1) : 0;
2959 n = strlen(msg);
2960
2961 levmsg = (char *) alloc(old_n + n + 1);
2962 if (old_n)
2963 levmsg[old_n - 1] = '\n';
2964 if (lev_message)
2965 (void) memcpy((genericptr_t) levmsg, (genericptr_t) lev_message,
2966 old_n - 1);
2967 (void) memcpy((genericptr_t) &levmsg[old_n], msg, n);
2968 levmsg[old_n + n] = '\0';
2969 Free(lev_message);
2970 lev_message = levmsg;
2971 opvar_free(op);
2972 }
2973
2974 void
spo_monster(coder)2975 spo_monster(coder)
2976 struct sp_coder *coder;
2977 {
2978 static const char nhFunc[] = "spo_monster";
2979 int nparams = 0;
2980 struct opvar *varparam;
2981 struct opvar *id, *mcoord, *has_inv;
2982 monster tmpmons;
2983
2984 tmpmons.peaceful = -1;
2985 tmpmons.asleep = -1;
2986 tmpmons.name.str = (char *) 0;
2987 tmpmons.appear = 0;
2988 tmpmons.appear_as.str = (char *) 0;
2989 tmpmons.align = -MAX_REGISTERS - 2;
2990 tmpmons.female = 0;
2991 tmpmons.invis = 0;
2992 tmpmons.cancelled = 0;
2993 tmpmons.revived = 0;
2994 tmpmons.avenge = 0;
2995 tmpmons.fleeing = 0;
2996 tmpmons.blinded = 0;
2997 tmpmons.paralyzed = 0;
2998 tmpmons.stunned = 0;
2999 tmpmons.confused = 0;
3000 tmpmons.seentraps = 0;
3001 tmpmons.has_invent = 0;
3002
3003 if (!OV_pop_i(has_inv))
3004 return;
3005
3006 if (!OV_pop_i(varparam))
3007 return;
3008
3009 while ((nparams++ < (SP_M_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT)
3010 && (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_M_V_END)) {
3011 struct opvar *parm = NULL;
3012
3013 OV_pop(parm);
3014 switch (OV_i(varparam)) {
3015 case SP_M_V_NAME:
3016 if ((OV_typ(parm) == SPOVAR_STRING) && !tmpmons.name.str)
3017 tmpmons.name.str = dupstr(OV_s(parm));
3018 break;
3019 case SP_M_V_APPEAR:
3020 if ((OV_typ(parm) == SPOVAR_INT) && !tmpmons.appear_as.str) {
3021 tmpmons.appear = OV_i(parm);
3022 opvar_free(parm);
3023 OV_pop(parm);
3024 tmpmons.appear_as.str = dupstr(OV_s(parm));
3025 }
3026 break;
3027 case SP_M_V_ASLEEP:
3028 if (OV_typ(parm) == SPOVAR_INT)
3029 tmpmons.asleep = OV_i(parm);
3030 break;
3031 case SP_M_V_ALIGN:
3032 if (OV_typ(parm) == SPOVAR_INT)
3033 tmpmons.align = OV_i(parm);
3034 break;
3035 case SP_M_V_PEACEFUL:
3036 if (OV_typ(parm) == SPOVAR_INT)
3037 tmpmons.peaceful = OV_i(parm);
3038 break;
3039 case SP_M_V_FEMALE:
3040 if (OV_typ(parm) == SPOVAR_INT)
3041 tmpmons.female = OV_i(parm);
3042 break;
3043 case SP_M_V_INVIS:
3044 if (OV_typ(parm) == SPOVAR_INT)
3045 tmpmons.invis = OV_i(parm);
3046 break;
3047 case SP_M_V_CANCELLED:
3048 if (OV_typ(parm) == SPOVAR_INT)
3049 tmpmons.cancelled = OV_i(parm);
3050 break;
3051 case SP_M_V_REVIVED:
3052 if (OV_typ(parm) == SPOVAR_INT)
3053 tmpmons.revived = OV_i(parm);
3054 break;
3055 case SP_M_V_AVENGE:
3056 if (OV_typ(parm) == SPOVAR_INT)
3057 tmpmons.avenge = OV_i(parm);
3058 break;
3059 case SP_M_V_FLEEING:
3060 if (OV_typ(parm) == SPOVAR_INT)
3061 tmpmons.fleeing = OV_i(parm);
3062 break;
3063 case SP_M_V_BLINDED:
3064 if (OV_typ(parm) == SPOVAR_INT)
3065 tmpmons.blinded = OV_i(parm);
3066 break;
3067 case SP_M_V_PARALYZED:
3068 if (OV_typ(parm) == SPOVAR_INT)
3069 tmpmons.paralyzed = OV_i(parm);
3070 break;
3071 case SP_M_V_STUNNED:
3072 if (OV_typ(parm) == SPOVAR_INT)
3073 tmpmons.stunned = OV_i(parm);
3074 break;
3075 case SP_M_V_CONFUSED:
3076 if (OV_typ(parm) == SPOVAR_INT)
3077 tmpmons.confused = OV_i(parm);
3078 break;
3079 case SP_M_V_SEENTRAPS:
3080 if (OV_typ(parm) == SPOVAR_INT)
3081 tmpmons.seentraps = OV_i(parm);
3082 break;
3083 case SP_M_V_END:
3084 nparams = SP_M_V_END + 1;
3085 break;
3086 default:
3087 impossible("MONSTER with unknown variable param type!");
3088 break;
3089 }
3090 opvar_free(parm);
3091 if (OV_i(varparam) != SP_M_V_END) {
3092 opvar_free(varparam);
3093 OV_pop(varparam);
3094 }
3095 }
3096
3097 if (!OV_pop_c(mcoord))
3098 panic("no monster coord?");
3099
3100 if (!OV_pop_typ(id, SPOVAR_MONST))
3101 panic("no mon type");
3102
3103 tmpmons.id = SP_MONST_PM(OV_i(id));
3104 tmpmons.class = SP_MONST_CLASS(OV_i(id));
3105 tmpmons.coord = OV_i(mcoord);
3106 tmpmons.has_invent = OV_i(has_inv);
3107
3108 create_monster(&tmpmons, coder->croom);
3109
3110 Free(tmpmons.name.str);
3111 Free(tmpmons.appear_as.str);
3112 opvar_free(id);
3113 opvar_free(mcoord);
3114 opvar_free(has_inv);
3115 opvar_free(varparam);
3116 }
3117
3118 void
spo_object(coder)3119 spo_object(coder)
3120 struct sp_coder *coder;
3121 {
3122 static const char nhFunc[] = "spo_object";
3123 int nparams = 0;
3124 long quancnt;
3125 struct opvar *varparam;
3126 struct opvar *id, *containment;
3127 object tmpobj;
3128
3129 tmpobj.spe = -127;
3130 tmpobj.curse_state = -1;
3131 tmpobj.corpsenm = NON_PM;
3132 tmpobj.name.str = (char *) 0;
3133 tmpobj.quan = -1;
3134 tmpobj.buried = 0;
3135 tmpobj.lit = 0;
3136 tmpobj.eroded = 0;
3137 tmpobj.locked = 0;
3138 tmpobj.trapped = -1;
3139 tmpobj.recharged = 0;
3140 tmpobj.invis = 0;
3141 tmpobj.greased = 0;
3142 tmpobj.broken = 0;
3143 tmpobj.coord = SP_COORD_PACK_RANDOM(0);
3144
3145 if (!OV_pop_i(containment))
3146 return;
3147
3148 if (!OV_pop_i(varparam))
3149 return;
3150
3151 while ((nparams++ < (SP_O_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT)
3152 && (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_O_V_END)) {
3153 struct opvar *parm;
3154
3155 OV_pop(parm);
3156 switch (OV_i(varparam)) {
3157 case SP_O_V_NAME:
3158 if ((OV_typ(parm) == SPOVAR_STRING) && !tmpobj.name.str)
3159 tmpobj.name.str = dupstr(OV_s(parm));
3160 break;
3161 case SP_O_V_CORPSENM:
3162 if (OV_typ(parm) == SPOVAR_MONST) {
3163 char monclass = SP_MONST_CLASS(OV_i(parm));
3164 int monid = SP_MONST_PM(OV_i(parm));
3165
3166 if (monid >= LOW_PM && monid < NUMMONS) {
3167 tmpobj.corpsenm = monid;
3168 break; /* we're done! */
3169 } else {
3170 struct permonst *pm = (struct permonst *) 0;
3171
3172 if (def_char_to_monclass(monclass) != MAXMCLASSES) {
3173 pm = mkclass(def_char_to_monclass(monclass), G_NOGEN);
3174 } else {
3175 pm = rndmonst();
3176 }
3177 if (pm)
3178 tmpobj.corpsenm = monsndx(pm);
3179 }
3180 }
3181 break;
3182 case SP_O_V_CURSE:
3183 if (OV_typ(parm) == SPOVAR_INT)
3184 tmpobj.curse_state = OV_i(parm);
3185 break;
3186 case SP_O_V_SPE:
3187 if (OV_typ(parm) == SPOVAR_INT)
3188 tmpobj.spe = OV_i(parm);
3189 break;
3190 case SP_O_V_QUAN:
3191 if (OV_typ(parm) == SPOVAR_INT)
3192 tmpobj.quan = OV_i(parm);
3193 break;
3194 case SP_O_V_BURIED:
3195 if (OV_typ(parm) == SPOVAR_INT)
3196 tmpobj.buried = OV_i(parm);
3197 break;
3198 case SP_O_V_LIT:
3199 if (OV_typ(parm) == SPOVAR_INT)
3200 tmpobj.lit = OV_i(parm);
3201 break;
3202 case SP_O_V_ERODED:
3203 if (OV_typ(parm) == SPOVAR_INT)
3204 tmpobj.eroded = OV_i(parm);
3205 break;
3206 case SP_O_V_LOCKED:
3207 if (OV_typ(parm) == SPOVAR_INT)
3208 tmpobj.locked = OV_i(parm);
3209 break;
3210 case SP_O_V_TRAPPED:
3211 if (OV_typ(parm) == SPOVAR_INT)
3212 tmpobj.trapped = OV_i(parm);
3213 break;
3214 case SP_O_V_RECHARGED:
3215 if (OV_typ(parm) == SPOVAR_INT)
3216 tmpobj.recharged = OV_i(parm);
3217 break;
3218 case SP_O_V_INVIS:
3219 if (OV_typ(parm) == SPOVAR_INT)
3220 tmpobj.invis = OV_i(parm);
3221 break;
3222 case SP_O_V_GREASED:
3223 if (OV_typ(parm) == SPOVAR_INT)
3224 tmpobj.greased = OV_i(parm);
3225 break;
3226 case SP_O_V_BROKEN:
3227 if (OV_typ(parm) == SPOVAR_INT)
3228 tmpobj.broken = OV_i(parm);
3229 break;
3230 case SP_O_V_COORD:
3231 if (OV_typ(parm) != SPOVAR_COORD)
3232 panic("no coord for obj?");
3233 tmpobj.coord = OV_i(parm);
3234 break;
3235 case SP_O_V_END:
3236 nparams = SP_O_V_END + 1;
3237 break;
3238 default:
3239 impossible("OBJECT with unknown variable param type!");
3240 break;
3241 }
3242 opvar_free(parm);
3243 if (OV_i(varparam) != SP_O_V_END) {
3244 opvar_free(varparam);
3245 OV_pop(varparam);
3246 }
3247 }
3248
3249 if (!OV_pop_typ(id, SPOVAR_OBJ))
3250 panic("no obj type");
3251
3252 tmpobj.id = SP_OBJ_TYP(OV_i(id));
3253 tmpobj.class = SP_OBJ_CLASS(OV_i(id));
3254 tmpobj.containment = OV_i(containment);
3255
3256 quancnt = (tmpobj.id > STRANGE_OBJECT) ? tmpobj.quan : 0;
3257
3258 do {
3259 create_object(&tmpobj, coder->croom);
3260 quancnt--;
3261 } while ((quancnt > 0) && ((tmpobj.id > STRANGE_OBJECT)
3262 && !objects[tmpobj.id].oc_merge));
3263
3264 Free(tmpobj.name.str);
3265 opvar_free(varparam);
3266 opvar_free(id);
3267 opvar_free(containment);
3268 }
3269
3270 void
spo_level_flags(coder)3271 spo_level_flags(coder)
3272 struct sp_coder *coder;
3273 {
3274 static const char nhFunc[] = "spo_level_flags";
3275 struct opvar *flagdata;
3276 long lflags;
3277
3278 if (!OV_pop_i(flagdata))
3279 return;
3280 lflags = OV_i(flagdata);
3281
3282 if (lflags & NOTELEPORT)
3283 level.flags.noteleport = 1;
3284 if (lflags & HARDFLOOR)
3285 level.flags.hardfloor = 1;
3286 if (lflags & NOMMAP)
3287 level.flags.nommap = 1;
3288 if (lflags & SHORTSIGHTED)
3289 level.flags.shortsighted = 1;
3290 if (lflags & ARBOREAL)
3291 level.flags.arboreal = 1;
3292 if (lflags & MAZELEVEL)
3293 level.flags.is_maze_lev = 1;
3294 if (lflags & PREMAPPED)
3295 coder->premapped = TRUE;
3296 if (lflags & SHROUD)
3297 level.flags.hero_memory = 0;
3298 if (lflags & GRAVEYARD)
3299 level.flags.graveyard = 1;
3300 if (lflags & ICEDPOOLS)
3301 icedpools = TRUE;
3302 if (lflags & SOLIDIFY)
3303 coder->solidify = TRUE;
3304 if (lflags & CORRMAZE)
3305 level.flags.corrmaze = TRUE;
3306 if (lflags & CHECK_INACCESSIBLES)
3307 coder->check_inaccessibles = TRUE;
3308
3309 opvar_free(flagdata);
3310 }
3311
3312 void
spo_initlevel(coder)3313 spo_initlevel(coder)
3314 struct sp_coder *coder;
3315 {
3316 static const char nhFunc[] = "spo_initlevel";
3317 lev_init init_lev;
3318 struct opvar *init_style, *fg, *bg, *smoothed, *joined, *lit, *walled,
3319 *filling;
3320
3321 if (!OV_pop_i(fg) || !OV_pop_i(bg) || !OV_pop_i(smoothed)
3322 || !OV_pop_i(joined) || !OV_pop_i(lit) || !OV_pop_i(walled)
3323 || !OV_pop_i(filling) || !OV_pop_i(init_style))
3324 return;
3325
3326 splev_init_present = TRUE;
3327
3328 init_lev.init_style = OV_i(init_style);
3329 init_lev.fg = OV_i(fg);
3330 init_lev.bg = OV_i(bg);
3331 init_lev.smoothed = OV_i(smoothed);
3332 init_lev.joined = OV_i(joined);
3333 init_lev.lit = OV_i(lit);
3334 init_lev.walled = OV_i(walled);
3335 init_lev.filling = OV_i(filling);
3336
3337 coder->lvl_is_joined = OV_i(joined);
3338
3339 splev_initlev(&init_lev);
3340
3341 opvar_free(init_style);
3342 opvar_free(fg);
3343 opvar_free(bg);
3344 opvar_free(smoothed);
3345 opvar_free(joined);
3346 opvar_free(lit);
3347 opvar_free(walled);
3348 opvar_free(filling);
3349 }
3350
3351 void
spo_engraving(coder)3352 spo_engraving(coder)
3353 struct sp_coder *coder;
3354 {
3355 static const char nhFunc[] = "spo_engraving";
3356 struct opvar *etyp, *txt, *ecoord;
3357 xchar x, y;
3358
3359 if (!OV_pop_i(etyp) || !OV_pop_s(txt) || !OV_pop_c(ecoord))
3360 return;
3361
3362 get_location_coord(&x, &y, DRY, coder->croom, OV_i(ecoord));
3363 make_engr_at(x, y, OV_s(txt), 0L, OV_i(etyp));
3364
3365 opvar_free(etyp);
3366 opvar_free(txt);
3367 opvar_free(ecoord);
3368 }
3369
3370 void
spo_mineralize(coder)3371 spo_mineralize(coder)
3372 struct sp_coder *coder;
3373 {
3374 static const char nhFunc[] = "spo_mineralize";
3375 struct opvar *kelp_pool, *kelp_moat, *gold_prob, *gem_prob;
3376
3377 if (!OV_pop_i(gem_prob) || !OV_pop_i(gold_prob) || !OV_pop_i(kelp_moat)
3378 || !OV_pop_i(kelp_pool))
3379 return;
3380
3381 mineralize(OV_i(kelp_pool), OV_i(kelp_moat), OV_i(gold_prob),
3382 OV_i(gem_prob), TRUE);
3383
3384 opvar_free(gem_prob);
3385 opvar_free(gold_prob);
3386 opvar_free(kelp_moat);
3387 opvar_free(kelp_pool);
3388 }
3389
3390 void
spo_room(coder)3391 spo_room(coder)
3392 struct sp_coder *coder;
3393 {
3394 static const char nhFunc[] = "spo_room";
3395
3396 if (coder->n_subroom > MAX_NESTED_ROOMS) {
3397 panic("Too deeply nested rooms?!");
3398 } else {
3399 struct opvar *rflags, *h, *w, *yalign, *xalign, *y, *x, *rlit,
3400 *chance, *rtype;
3401 room tmproom;
3402 struct mkroom *tmpcr;
3403
3404 if (!OV_pop_i(h) || !OV_pop_i(w) || !OV_pop_i(y) || !OV_pop_i(x)
3405 || !OV_pop_i(yalign) || !OV_pop_i(xalign) || !OV_pop_i(rflags)
3406 || !OV_pop_i(rlit) || !OV_pop_i(chance) || !OV_pop_i(rtype))
3407 return;
3408
3409 tmproom.x = OV_i(x);
3410 tmproom.y = OV_i(y);
3411 tmproom.w = OV_i(w);
3412 tmproom.h = OV_i(h);
3413 tmproom.xalign = OV_i(xalign);
3414 tmproom.yalign = OV_i(yalign);
3415 tmproom.rtype = OV_i(rtype);
3416 tmproom.chance = OV_i(chance);
3417 tmproom.rlit = OV_i(rlit);
3418 tmproom.filled = (OV_i(rflags) & (1 << 0));
3419 /*tmproom.irregular = (OV_i(rflags) & (1 << 1));*/
3420 tmproom.joined = !(OV_i(rflags) & (1 << 2));
3421
3422 opvar_free(x);
3423 opvar_free(y);
3424 opvar_free(w);
3425 opvar_free(h);
3426 opvar_free(xalign);
3427 opvar_free(yalign);
3428 opvar_free(rtype);
3429 opvar_free(chance);
3430 opvar_free(rlit);
3431 opvar_free(rflags);
3432
3433 if (!coder->failed_room[coder->n_subroom - 1]) {
3434 tmpcr = build_room(&tmproom, coder->croom);
3435 if (tmpcr) {
3436 coder->tmproomlist[coder->n_subroom] = tmpcr;
3437 coder->failed_room[coder->n_subroom] = FALSE;
3438 coder->n_subroom++;
3439 return;
3440 }
3441 } /* failed to create parent room, so fail this too */
3442 }
3443 coder->tmproomlist[coder->n_subroom] = (struct mkroom *) 0;
3444 coder->failed_room[coder->n_subroom] = TRUE;
3445 coder->n_subroom++;
3446 }
3447
3448 void
spo_endroom(coder)3449 spo_endroom(coder)
3450 struct sp_coder *coder;
3451 {
3452 if (coder->n_subroom > 1) {
3453 coder->n_subroom--;
3454 coder->tmproomlist[coder->n_subroom] = NULL;
3455 coder->failed_room[coder->n_subroom] = TRUE;
3456 } else {
3457 /* no subroom, get out of top-level room */
3458 /* Need to ensure xstart/ystart/xsize/ysize have something sensible,
3459 in case there's some stuff to be created outside the outermost
3460 room,
3461 and there's no MAP.
3462 */
3463 if (xsize <= 1 && ysize <= 1) {
3464 xstart = 1;
3465 ystart = 0;
3466 xsize = COLNO - 1;
3467 ysize = ROWNO;
3468 }
3469 }
3470 }
3471
3472 void
spo_stair(coder)3473 spo_stair(coder)
3474 struct sp_coder *coder;
3475 {
3476 static const char nhFunc[] = "spo_stair";
3477 xchar x, y;
3478 struct opvar *up, *scoord;
3479 struct trap *badtrap;
3480
3481 if (!OV_pop_i(up) || !OV_pop_c(scoord))
3482 return;
3483
3484 get_location_coord(&x, &y, DRY, coder->croom, OV_i(scoord));
3485 if ((badtrap = t_at(x, y)) != 0)
3486 deltrap(badtrap);
3487 mkstairs(x, y, (char) OV_i(up), coder->croom);
3488 SpLev_Map[x][y] = 1;
3489
3490 opvar_free(scoord);
3491 opvar_free(up);
3492 }
3493
3494 void
spo_ladder(coder)3495 spo_ladder(coder)
3496 struct sp_coder *coder;
3497 {
3498 static const char nhFunc[] = "spo_ladder";
3499 xchar x, y;
3500 struct opvar *up, *lcoord;
3501
3502 if (!OV_pop_i(up) || !OV_pop_c(lcoord))
3503 return;
3504
3505 get_location_coord(&x, &y, DRY, coder->croom, OV_i(lcoord));
3506
3507 levl[x][y].typ = LADDER;
3508 SpLev_Map[x][y] = 1;
3509 if (OV_i(up)) {
3510 xupladder = x;
3511 yupladder = y;
3512 levl[x][y].ladder = LA_UP;
3513 } else {
3514 xdnladder = x;
3515 ydnladder = y;
3516 levl[x][y].ladder = LA_DOWN;
3517 }
3518 opvar_free(lcoord);
3519 opvar_free(up);
3520 }
3521
3522 void
spo_grave(coder)3523 spo_grave(coder)
3524 struct sp_coder *coder;
3525 {
3526 static const char nhFunc[] = "spo_grave";
3527 struct opvar *gcoord, *typ, *txt;
3528 schar x, y;
3529
3530 if (!OV_pop_i(typ) || !OV_pop_s(txt) || !OV_pop_c(gcoord))
3531 return;
3532
3533 get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord));
3534
3535 if (isok(x, y) && !t_at(x, y)) {
3536 levl[x][y].typ = GRAVE;
3537 switch (OV_i(typ)) {
3538 case 2:
3539 make_grave(x, y, OV_s(txt));
3540 break;
3541 case 1:
3542 make_grave(x, y, NULL);
3543 break;
3544 default:
3545 del_engr_at(x, y);
3546 break;
3547 }
3548 }
3549
3550 opvar_free(gcoord);
3551 opvar_free(typ);
3552 opvar_free(txt);
3553 }
3554
3555 void
spo_altar(coder)3556 spo_altar(coder)
3557 struct sp_coder *coder;
3558 {
3559 static const char nhFunc[] = "spo_altar";
3560 struct opvar *al, *shrine, *acoord;
3561 altar tmpaltar;
3562
3563 if (!OV_pop_i(al) || !OV_pop_i(shrine) || !OV_pop_c(acoord))
3564 return;
3565
3566 tmpaltar.coord = OV_i(acoord);
3567 tmpaltar.align = OV_i(al);
3568 tmpaltar.shrine = OV_i(shrine);
3569
3570 create_altar(&tmpaltar, coder->croom);
3571
3572 opvar_free(acoord);
3573 opvar_free(shrine);
3574 opvar_free(al);
3575 }
3576
3577 void
spo_trap(coder)3578 spo_trap(coder)
3579 struct sp_coder *coder;
3580 {
3581 static const char nhFunc[] = "spo_trap";
3582 struct opvar *type;
3583 struct opvar *tcoord;
3584 spltrap tmptrap;
3585
3586 if (!OV_pop_i(type) || !OV_pop_c(tcoord))
3587 return;
3588
3589 tmptrap.coord = OV_i(tcoord);
3590 tmptrap.type = OV_i(type);
3591
3592 create_trap(&tmptrap, coder->croom);
3593 opvar_free(tcoord);
3594 opvar_free(type);
3595 }
3596
3597 void
spo_gold(coder)3598 spo_gold(coder)
3599 struct sp_coder *coder;
3600 {
3601 static const char nhFunc[] = "spo_gold";
3602 struct opvar *gcoord, *amt;
3603 schar x, y;
3604 long amount;
3605
3606 if (!OV_pop_c(gcoord) || !OV_pop_i(amt))
3607 return;
3608 amount = OV_i(amt);
3609 get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord));
3610 if (amount == -1)
3611 amount = rnd(200);
3612 mkgold(amount, x, y);
3613 opvar_free(gcoord);
3614 opvar_free(amt);
3615 }
3616
3617 void
spo_corridor(coder)3618 spo_corridor(coder)
3619 struct sp_coder *coder;
3620 {
3621 static const char nhFunc[] = "spo_corridor";
3622 struct opvar *deswall, *desdoor, *desroom, *srcwall, *srcdoor, *srcroom;
3623 corridor tc;
3624
3625 if (!OV_pop_i(deswall) || !OV_pop_i(desdoor) || !OV_pop_i(desroom)
3626 || !OV_pop_i(srcwall) || !OV_pop_i(srcdoor) || !OV_pop_i(srcroom))
3627 return;
3628
3629 tc.src.room = OV_i(srcroom);
3630 tc.src.door = OV_i(srcdoor);
3631 tc.src.wall = OV_i(srcwall);
3632 tc.dest.room = OV_i(desroom);
3633 tc.dest.door = OV_i(desdoor);
3634 tc.dest.wall = OV_i(deswall);
3635
3636 create_corridor(&tc);
3637
3638 opvar_free(deswall);
3639 opvar_free(desdoor);
3640 opvar_free(desroom);
3641 opvar_free(srcwall);
3642 opvar_free(srcdoor);
3643 opvar_free(srcroom);
3644 }
3645
3646 struct opvar *
selection_opvar(nbuf)3647 selection_opvar(nbuf)
3648 char *nbuf;
3649 {
3650 struct opvar *ov;
3651 char buf[(COLNO * ROWNO) + 1];
3652
3653 if (!nbuf) {
3654 (void) memset(buf, 1, sizeof(buf));
3655 buf[(COLNO * ROWNO)] = '\0';
3656 ov = opvar_new_str(buf);
3657 } else {
3658 ov = opvar_new_str(nbuf);
3659 }
3660 ov->spovartyp = SPOVAR_SEL;
3661 return ov;
3662 }
3663
3664 xchar
selection_getpoint(x,y,ov)3665 selection_getpoint(x, y, ov)
3666 int x, y;
3667 struct opvar *ov;
3668 {
3669 if (!ov || ov->spovartyp != SPOVAR_SEL)
3670 return 0;
3671 if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
3672 return 0;
3673
3674 return (ov->vardata.str[COLNO * y + x] - 1);
3675 }
3676
3677 void
selection_setpoint(x,y,ov,c)3678 selection_setpoint(x, y, ov, c)
3679 int x, y;
3680 struct opvar *ov;
3681 xchar c;
3682 {
3683 if (!ov || ov->spovartyp != SPOVAR_SEL)
3684 return;
3685 if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
3686 return;
3687
3688 ov->vardata.str[COLNO * y + x] = (char) (c + 1);
3689 }
3690
3691 struct opvar *
selection_not(s)3692 selection_not(s)
3693 struct opvar *s;
3694 {
3695 struct opvar *ov;
3696 int x, y;
3697
3698 ov = selection_opvar((char *) 0);
3699 if (!ov)
3700 return NULL;
3701
3702 for (x = 0; x < COLNO; x++)
3703 for (y = 0; y < ROWNO; y++)
3704 if (!selection_getpoint(x, y, s))
3705 selection_setpoint(x, y, ov, 1);
3706
3707 return ov;
3708 }
3709
3710 struct opvar *
selection_logical_oper(s1,s2,oper)3711 selection_logical_oper(s1, s2, oper)
3712 struct opvar *s1, *s2;
3713 char oper;
3714 {
3715 struct opvar *ov;
3716 int x, y;
3717
3718 ov = selection_opvar((char *) 0);
3719 if (!ov)
3720 return NULL;
3721
3722 for (x = 0; x < COLNO; x++)
3723 for (y = 0; y < ROWNO; y++) {
3724 switch (oper) {
3725 default:
3726 case '|':
3727 if (selection_getpoint(x, y, s1)
3728 || selection_getpoint(x, y, s2))
3729 selection_setpoint(x, y, ov, 1);
3730 break;
3731 case '&':
3732 if (selection_getpoint(x, y, s1)
3733 && selection_getpoint(x, y, s2))
3734 selection_setpoint(x, y, ov, 1);
3735 break;
3736 }
3737 }
3738
3739 return ov;
3740 }
3741
3742 struct opvar *
selection_filter_mapchar(ov,mc)3743 selection_filter_mapchar(ov, mc)
3744 struct opvar *ov;
3745 struct opvar *mc;
3746 {
3747 int x, y;
3748 schar mapc;
3749 xchar lit;
3750 struct opvar *ret = selection_opvar((char *) 0);
3751
3752 if (!ov || !mc || !ret)
3753 return NULL;
3754 mapc = SP_MAPCHAR_TYP(OV_i(mc));
3755 lit = SP_MAPCHAR_LIT(OV_i(mc));
3756 for (x = 0; x < COLNO; x++)
3757 for (y = 0; y < ROWNO; y++)
3758 if (selection_getpoint(x, y, ov) && (levl[x][y].typ == mapc)) {
3759 switch (lit) {
3760 default:
3761 case -2:
3762 selection_setpoint(x, y, ret, 1);
3763 break;
3764 case -1:
3765 selection_setpoint(x, y, ret, rn2(2));
3766 break;
3767 case 0:
3768 case 1:
3769 if (levl[x][y].lit == lit)
3770 selection_setpoint(x, y, ret, 1);
3771 break;
3772 }
3773 }
3774 return ret;
3775 }
3776
3777 void
selection_filter_percent(ov,percent)3778 selection_filter_percent(ov, percent)
3779 struct opvar *ov;
3780 int percent;
3781 {
3782 int x, y;
3783
3784 if (!ov)
3785 return;
3786 for (x = 0; x < COLNO; x++)
3787 for (y = 0; y < ROWNO; y++)
3788 if (selection_getpoint(x, y, ov) && (rn2(100) >= percent))
3789 selection_setpoint(x, y, ov, 0);
3790 }
3791
3792 STATIC_OVL int
selection_rndcoord(ov,x,y,removeit)3793 selection_rndcoord(ov, x, y, removeit)
3794 struct opvar *ov;
3795 schar *x, *y;
3796 boolean removeit;
3797 {
3798 int idx = 0;
3799 int c;
3800 int dx, dy;
3801
3802 for (dx = 0; dx < COLNO; dx++)
3803 for (dy = 0; dy < ROWNO; dy++)
3804 if (isok(dx, dy) && selection_getpoint(dx, dy, ov))
3805 idx++;
3806
3807 if (idx) {
3808 c = rn2(idx);
3809 for (dx = 0; dx < COLNO; dx++)
3810 for (dy = 0; dy < ROWNO; dy++)
3811 if (isok(dx, dy) && selection_getpoint(dx, dy, ov)) {
3812 if (!c) {
3813 *x = dx;
3814 *y = dy;
3815 if (removeit) selection_setpoint(dx, dy, ov, 0);
3816 return 1;
3817 }
3818 c--;
3819 }
3820 }
3821 *x = *y = -1;
3822 return 0;
3823 }
3824
3825 void
selection_do_grow(ov,dir)3826 selection_do_grow(ov, dir)
3827 struct opvar *ov;
3828 int dir;
3829 {
3830 int x, y;
3831 char tmp[COLNO][ROWNO];
3832
3833 if (ov->spovartyp != SPOVAR_SEL)
3834 return;
3835 if (!ov)
3836 return;
3837
3838 (void) memset(tmp, 0, sizeof tmp);
3839
3840 for (x = 1; x < COLNO; x++)
3841 for (y = 0; y < ROWNO; y++) {
3842 /* note: dir is a mask of multiple directions, but the only
3843 way to specify diagonals is by including the two adjacent
3844 orthogonal directions, which effectively specifies three-
3845 way growth [WEST|NORTH => WEST plus WEST|NORTH plus NORTH] */
3846 if (((dir & W_WEST) && selection_getpoint(x + 1, y, ov))
3847 || (((dir & (W_WEST | W_NORTH)) == (W_WEST | W_NORTH))
3848 && selection_getpoint(x + 1, y + 1, ov))
3849 || ((dir & W_NORTH) && selection_getpoint(x, y + 1, ov))
3850 || (((dir & (W_NORTH | W_EAST)) == (W_NORTH | W_EAST))
3851 && selection_getpoint(x - 1, y + 1, ov))
3852 || ((dir & W_EAST) && selection_getpoint(x - 1, y, ov))
3853 || (((dir & (W_EAST | W_SOUTH)) == (W_EAST | W_SOUTH))
3854 && selection_getpoint(x - 1, y - 1, ov))
3855 || ((dir & W_SOUTH) && selection_getpoint(x, y - 1, ov))
3856 || (((dir & (W_SOUTH | W_WEST)) == (W_SOUTH | W_WEST))
3857 && selection_getpoint(x + 1, y - 1, ov))) {
3858 tmp[x][y] = 1;
3859 }
3860 }
3861
3862 for (x = 1; x < COLNO; x++)
3863 for (y = 0; y < ROWNO; y++)
3864 if (tmp[x][y])
3865 selection_setpoint(x, y, ov, 1);
3866 }
3867
3868 STATIC_VAR int FDECL((*selection_flood_check_func), (int, int));
3869 STATIC_VAR schar floodfillchk_match_under_typ;
3870
3871 void
3872 set_selection_floodfillchk(f)
3873 int FDECL((*f), (int, int));
3874 {
3875 selection_flood_check_func = f;
3876 }
3877
3878 STATIC_OVL int
floodfillchk_match_under(x,y)3879 floodfillchk_match_under(x,y)
3880 int x,y;
3881 {
3882 return (floodfillchk_match_under_typ == levl[x][y].typ);
3883 }
3884
3885 STATIC_OVL int
floodfillchk_match_accessible(x,y)3886 floodfillchk_match_accessible(x, y)
3887 int x, y;
3888 {
3889 return (ACCESSIBLE(levl[x][y].typ)
3890 || levl[x][y].typ == SDOOR
3891 || levl[x][y].typ == SCORR);
3892 }
3893
3894 /* check whethere <x,y> is already in xs[],ys[] */
3895 STATIC_OVL boolean
sel_flood_havepoint(x,y,xs,ys,n)3896 sel_flood_havepoint(x, y, xs, ys, n)
3897 int x, y;
3898 xchar xs[], ys[];
3899 int n;
3900 {
3901 xchar xx = (xchar) x, yy = (xchar) y;
3902
3903 while (n > 0) {
3904 --n;
3905 if (xs[n] == xx && ys[n] == yy)
3906 return TRUE;
3907 }
3908 return FALSE;
3909 }
3910
3911 void
selection_floodfill(ov,x,y,diagonals)3912 selection_floodfill(ov, x, y, diagonals)
3913 struct opvar *ov;
3914 int x, y;
3915 boolean diagonals;
3916 {
3917 static const char nhFunc[] = "selection_floodfill";
3918 struct opvar *tmp = selection_opvar((char *) 0);
3919 #define SEL_FLOOD_STACK (COLNO * ROWNO)
3920 #define SEL_FLOOD(nx, ny) \
3921 do { \
3922 if (idx < SEL_FLOOD_STACK) { \
3923 dx[idx] = (nx); \
3924 dy[idx] = (ny); \
3925 idx++; \
3926 } else \
3927 panic(floodfill_stack_overrun); \
3928 } while (0)
3929 #define SEL_FLOOD_CHKDIR(mx, my, sel) \
3930 do { \
3931 if (isok((mx), (my)) \
3932 && (*selection_flood_check_func)((mx), (my)) \
3933 && !selection_getpoint((mx), (my), (sel)) \
3934 && !sel_flood_havepoint((mx), (my), dx, dy, idx)) \
3935 SEL_FLOOD((mx), (my)); \
3936 } while (0)
3937 static const char floodfill_stack_overrun[] = "floodfill stack overrun";
3938 int idx = 0;
3939 xchar dx[SEL_FLOOD_STACK];
3940 xchar dy[SEL_FLOOD_STACK];
3941
3942 if (selection_flood_check_func == (int FDECL((*), (int, int))) 0) {
3943 opvar_free(tmp);
3944 return;
3945 }
3946 SEL_FLOOD(x, y);
3947 do {
3948 idx--;
3949 x = dx[idx];
3950 y = dy[idx];
3951 if (isok(x, y)) {
3952 selection_setpoint(x, y, ov, 1);
3953 selection_setpoint(x, y, tmp, 1);
3954 }
3955 SEL_FLOOD_CHKDIR((x + 1), y, tmp);
3956 SEL_FLOOD_CHKDIR((x - 1), y, tmp);
3957 SEL_FLOOD_CHKDIR(x, (y + 1), tmp);
3958 SEL_FLOOD_CHKDIR(x, (y - 1), tmp);
3959 if (diagonals) {
3960 SEL_FLOOD_CHKDIR((x + 1), (y + 1), tmp);
3961 SEL_FLOOD_CHKDIR((x - 1), (y - 1), tmp);
3962 SEL_FLOOD_CHKDIR((x - 1), (y + 1), tmp);
3963 SEL_FLOOD_CHKDIR((x + 1), (y - 1), tmp);
3964 }
3965 } while (idx > 0);
3966 #undef SEL_FLOOD
3967 #undef SEL_FLOOD_STACK
3968 #undef SEL_FLOOD_CHKDIR
3969 opvar_free(tmp);
3970 }
3971
3972 /* McIlroy's Ellipse Algorithm */
3973 void
selection_do_ellipse(ov,xc,yc,a,b,filled)3974 selection_do_ellipse(ov, xc, yc, a, b, filled)
3975 struct opvar *ov;
3976 int xc, yc, a, b, filled;
3977 { /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
3978 int x = 0, y = b;
3979 long a2 = (long) a * a, b2 = (long) b * b;
3980 long crit1 = -(a2 / 4 + a % 2 + b2);
3981 long crit2 = -(b2 / 4 + b % 2 + a2);
3982 long crit3 = -(b2 / 4 + b % 2);
3983 long t = -a2 * y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
3984 long dxt = 2 * b2 * x, dyt = -2 * a2 * y;
3985 long d2xt = 2 * b2, d2yt = 2 * a2;
3986 long width = 1;
3987 long i;
3988
3989 if (!ov)
3990 return;
3991
3992 filled = !filled;
3993
3994 if (!filled) {
3995 while (y >= 0 && x <= a) {
3996 selection_setpoint(xc + x, yc + y, ov, 1);
3997 if (x != 0 || y != 0)
3998 selection_setpoint(xc - x, yc - y, ov, 1);
3999 if (x != 0 && y != 0) {
4000 selection_setpoint(xc + x, yc - y, ov, 1);
4001 selection_setpoint(xc - x, yc + y, ov, 1);
4002 }
4003 if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
4004 || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
4005 x++;
4006 dxt += d2xt;
4007 t += dxt;
4008 } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
4009 y--;
4010 dyt += d2yt;
4011 t += dyt;
4012 } else {
4013 x++;
4014 dxt += d2xt;
4015 t += dxt;
4016 y--;
4017 dyt += d2yt;
4018 t += dyt;
4019 }
4020 }
4021 } else {
4022 while (y >= 0 && x <= a) {
4023 if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
4024 || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
4025 x++;
4026 dxt += d2xt;
4027 t += dxt;
4028 width += 2;
4029 } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
4030 for (i = 0; i < width; i++)
4031 selection_setpoint(xc - x + i, yc - y, ov, 1);
4032 if (y != 0)
4033 for (i = 0; i < width; i++)
4034 selection_setpoint(xc - x + i, yc + y, ov, 1);
4035 y--;
4036 dyt += d2yt;
4037 t += dyt;
4038 } else {
4039 for (i = 0; i < width; i++)
4040 selection_setpoint(xc - x + i, yc - y, ov, 1);
4041 if (y != 0)
4042 for (i = 0; i < width; i++)
4043 selection_setpoint(xc - x + i, yc + y, ov, 1);
4044 x++;
4045 dxt += d2xt;
4046 t += dxt;
4047 y--;
4048 dyt += d2yt;
4049 t += dyt;
4050 width += 2;
4051 }
4052 }
4053 }
4054 }
4055
4056 /* distance from line segment (x1,y1, x2,y2) to point (x3,y3) */
4057 long
line_dist_coord(x1,y1,x2,y2,x3,y3)4058 line_dist_coord(x1, y1, x2, y2, x3, y3)
4059 long x1, y1, x2, y2, x3, y3;
4060 {
4061 long px = x2 - x1;
4062 long py = y2 - y1;
4063 long s = px * px + py * py;
4064 long x, y, dx, dy, dist = 0;
4065 float lu = 0;
4066
4067 if (x1 == x2 && y1 == y2)
4068 return isqrt(dist2(x1, y1, x3, y3));
4069
4070 lu = ((x3 - x1) * px + (y3 - y1) * py) / (float) s;
4071 if (lu > 1)
4072 lu = 1;
4073 else if (lu < 0)
4074 lu = 0;
4075
4076 x = x1 + lu * px;
4077 y = y1 + lu * py;
4078 dx = x - x3;
4079 dy = y - y3;
4080 dist = isqrt(dx * dx + dy * dy);
4081
4082 return dist;
4083 }
4084
4085 void
selection_do_gradient(ov,x,y,x2,y2,gtyp,mind,maxd,limit)4086 selection_do_gradient(ov, x, y, x2, y2, gtyp, mind, maxd, limit)
4087 struct opvar *ov;
4088 long x, y, x2, y2, gtyp, mind, maxd, limit;
4089 {
4090 long dx, dy, dofs;
4091
4092 if (mind > maxd) {
4093 long tmp = mind;
4094 mind = maxd;
4095 maxd = tmp;
4096 }
4097
4098 dofs = maxd - mind;
4099 if (dofs < 1)
4100 dofs = 1;
4101
4102 switch (gtyp) {
4103 default:
4104 case SEL_GRADIENT_RADIAL: {
4105 for (dx = 0; dx < COLNO; dx++)
4106 for (dy = 0; dy < ROWNO; dy++) {
4107 long d0 = line_dist_coord(x, y, x2, y2, dx, dy);
4108 if (d0 >= mind && (!limit || d0 <= maxd)) {
4109 if (d0 - mind > rn2(dofs))
4110 selection_setpoint(dx, dy, ov, 1);
4111 }
4112 }
4113 break;
4114 }
4115 case SEL_GRADIENT_SQUARE: {
4116 for (dx = 0; dx < COLNO; dx++)
4117 for (dy = 0; dy < ROWNO; dy++) {
4118 long d1 = line_dist_coord(x, y, x2, y2, x, dy);
4119 long d2 = line_dist_coord(x, y, x2, y2, dx, y);
4120 long d3 = line_dist_coord(x, y, x2, y2, x2, dy);
4121 long d4 = line_dist_coord(x, y, x2, y2, dx, y2);
4122 long d5 = line_dist_coord(x, y, x2, y2, dx, dy);
4123 long d0 = min(d5, min(max(d1, d2), max(d3, d4)));
4124
4125 if (d0 >= mind && (!limit || d0 <= maxd)) {
4126 if (d0 - mind > rn2(dofs))
4127 selection_setpoint(dx, dy, ov, 1);
4128 }
4129 }
4130 break;
4131 } /*case*/
4132 } /*switch*/
4133 }
4134
4135 /* bresenham line algo */
4136 void
selection_do_line(x1,y1,x2,y2,ov)4137 selection_do_line(x1, y1, x2, y2, ov)
4138 schar x1, y1, x2, y2;
4139 struct opvar *ov;
4140 {
4141 int d0, dx, dy, ai, bi, xi, yi;
4142
4143 if (x1 < x2) {
4144 xi = 1;
4145 dx = x2 - x1;
4146 } else {
4147 xi = -1;
4148 dx = x1 - x2;
4149 }
4150
4151 if (y1 < y2) {
4152 yi = 1;
4153 dy = y2 - y1;
4154 } else {
4155 yi = -1;
4156 dy = y1 - y2;
4157 }
4158
4159 selection_setpoint(x1, y1, ov, 1);
4160
4161 if (dx > dy) {
4162 ai = (dy - dx) * 2;
4163 bi = dy * 2;
4164 d0 = bi - dx;
4165 do {
4166 if (d0 >= 0) {
4167 y1 += yi;
4168 d0 += ai;
4169 } else
4170 d0 += bi;
4171 x1 += xi;
4172 selection_setpoint(x1, y1, ov, 1);
4173 } while (x1 != x2);
4174 } else {
4175 ai = (dx - dy) * 2;
4176 bi = dx * 2;
4177 d0 = bi - dy;
4178 do {
4179 if (d0 >= 0) {
4180 x1 += xi;
4181 d0 += ai;
4182 } else
4183 d0 += bi;
4184 y1 += yi;
4185 selection_setpoint(x1, y1, ov, 1);
4186 } while (y1 != y2);
4187 }
4188 }
4189
4190 void
selection_do_randline(x1,y1,x2,y2,rough,rec,ov)4191 selection_do_randline(x1, y1, x2, y2, rough, rec, ov)
4192 schar x1, y1, x2, y2, rough, rec;
4193 struct opvar *ov;
4194 {
4195 int mx, my;
4196 int dx, dy;
4197
4198 if (rec < 1) {
4199 return;
4200 }
4201
4202 if ((x2 == x1) && (y2 == y1)) {
4203 selection_setpoint(x1, y1, ov, 1);
4204 return;
4205 }
4206
4207 if (rough > max(abs(x2 - x1), abs(y2 - y1)))
4208 rough = max(abs(x2 - x1), abs(y2 - y1));
4209
4210 if (rough < 2) {
4211 mx = ((x1 + x2) / 2);
4212 my = ((y1 + y2) / 2);
4213 } else {
4214 do {
4215 dx = rn2(rough) - (rough / 2);
4216 dy = rn2(rough) - (rough / 2);
4217 mx = ((x1 + x2) / 2) + dx;
4218 my = ((y1 + y2) / 2) + dy;
4219 } while ((mx > COLNO - 1 || mx < 0 || my < 0 || my > ROWNO - 1));
4220 }
4221
4222 selection_setpoint(mx, my, ov, 1);
4223
4224 rough = (rough * 2) / 3;
4225
4226 rec--;
4227
4228 selection_do_randline(x1, y1, mx, my, rough, rec, ov);
4229 selection_do_randline(mx, my, x2, y2, rough, rec, ov);
4230 }
4231
4232 void
selection_iterate(ov,func,arg)4233 selection_iterate(ov, func, arg)
4234 struct opvar *ov;
4235 select_iter_func func;
4236 genericptr_t arg;
4237 {
4238 int x, y;
4239
4240 /* yes, this is very naive, but it's not _that_ expensive. */
4241 for (x = 0; x < COLNO; x++)
4242 for (y = 0; y < ROWNO; y++)
4243 if (selection_getpoint(x, y, ov))
4244 (*func)(x, y, arg);
4245 }
4246
4247 void
sel_set_ter(x,y,arg)4248 sel_set_ter(x, y, arg)
4249 int x, y;
4250 genericptr_t arg;
4251 {
4252 terrain terr;
4253
4254 terr = *(terrain *) arg;
4255 SET_TYPLIT(x, y, terr.ter, terr.tlit);
4256 /* handle doors and secret doors */
4257 if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
4258 if (levl[x][y].typ == SDOOR)
4259 levl[x][y].doormask = D_CLOSED;
4260 if (x && (IS_WALL(levl[x - 1][y].typ) || levl[x - 1][y].horizontal))
4261 levl[x][y].horizontal = 1;
4262 }
4263 }
4264
4265 void
sel_set_feature(x,y,arg)4266 sel_set_feature(x, y, arg)
4267 int x, y;
4268 genericptr_t arg;
4269 {
4270 if (IS_FURNITURE(levl[x][y].typ))
4271 return;
4272 levl[x][y].typ = (*(int *) arg);
4273 }
4274
4275 void
sel_set_door(dx,dy,arg)4276 sel_set_door(dx, dy, arg)
4277 int dx, dy;
4278 genericptr_t arg;
4279 {
4280 xchar typ = *(xchar *) arg;
4281 xchar x = dx, y = dy;
4282
4283 if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR)
4284 levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR;
4285 if (typ & D_SECRET) {
4286 typ &= ~D_SECRET;
4287 if (typ < D_CLOSED)
4288 typ = D_CLOSED;
4289 }
4290 set_door_orientation(x, y); /* set/clear levl[x][y].horizontal */
4291 levl[x][y].doormask = typ;
4292 SpLev_Map[x][y] = 1;
4293 }
4294
4295 void
spo_door(coder)4296 spo_door(coder)
4297 struct sp_coder *coder;
4298 {
4299 static const char nhFunc[] = "spo_door";
4300 struct opvar *msk, *sel;
4301 xchar typ;
4302
4303 if (!OV_pop_i(msk) || !OV_pop_typ(sel, SPOVAR_SEL))
4304 return;
4305
4306 typ = OV_i(msk) == -1 ? rnddoor() : (xchar) OV_i(msk);
4307
4308 selection_iterate(sel, sel_set_door, (genericptr_t) &typ);
4309
4310 opvar_free(sel);
4311 opvar_free(msk);
4312 }
4313
4314 void
spo_feature(coder)4315 spo_feature(coder)
4316 struct sp_coder *coder;
4317 {
4318 static const char nhFunc[] = "spo_feature";
4319 struct opvar *sel;
4320 int typ;
4321
4322 if (!OV_pop_typ(sel, SPOVAR_SEL))
4323 return;
4324
4325 switch (coder->opcode) {
4326 default:
4327 impossible("spo_feature called with wrong opcode %i.", coder->opcode);
4328 break;
4329 case SPO_FOUNTAIN:
4330 typ = FOUNTAIN;
4331 break;
4332 case SPO_SINK:
4333 typ = SINK;
4334 break;
4335 case SPO_POOL:
4336 typ = POOL;
4337 break;
4338 }
4339 selection_iterate(sel, sel_set_feature, (genericptr_t) &typ);
4340 opvar_free(sel);
4341 }
4342
4343 void
spo_terrain(coder)4344 spo_terrain(coder)
4345 struct sp_coder *coder;
4346 {
4347 static const char nhFunc[] = "spo_terrain";
4348 terrain tmpterrain;
4349 struct opvar *ter, *sel;
4350
4351 if (!OV_pop_typ(ter, SPOVAR_MAPCHAR) || !OV_pop_typ(sel, SPOVAR_SEL))
4352 return;
4353
4354 tmpterrain.ter = SP_MAPCHAR_TYP(OV_i(ter));
4355 tmpterrain.tlit = SP_MAPCHAR_LIT(OV_i(ter));
4356 selection_iterate(sel, sel_set_ter, (genericptr_t) &tmpterrain);
4357
4358 opvar_free(ter);
4359 opvar_free(sel);
4360 }
4361
4362 void
spo_replace_terrain(coder)4363 spo_replace_terrain(coder)
4364 struct sp_coder *coder;
4365 {
4366 static const char nhFunc[] = "spo_replace_terrain";
4367 replaceterrain rt;
4368 struct opvar *reg, *from_ter, *to_ter, *chance;
4369
4370 if (!OV_pop_i(chance) || !OV_pop_typ(to_ter, SPOVAR_MAPCHAR)
4371 || !OV_pop_typ(from_ter, SPOVAR_MAPCHAR) || !OV_pop_r(reg))
4372 return;
4373
4374 rt.chance = OV_i(chance);
4375 rt.tolit = SP_MAPCHAR_LIT(OV_i(to_ter));
4376 rt.toter = SP_MAPCHAR_TYP(OV_i(to_ter));
4377 rt.fromter = SP_MAPCHAR_TYP(OV_i(from_ter));
4378 /* TODO: use SP_MAPCHAR_LIT(OV_i(from_ter)) too */
4379 rt.x1 = SP_REGION_X1(OV_i(reg));
4380 rt.y1 = SP_REGION_Y1(OV_i(reg));
4381 rt.x2 = SP_REGION_X2(OV_i(reg));
4382 rt.y2 = SP_REGION_Y2(OV_i(reg));
4383
4384 replace_terrain(&rt, coder->croom);
4385
4386 opvar_free(reg);
4387 opvar_free(from_ter);
4388 opvar_free(to_ter);
4389 opvar_free(chance);
4390 }
4391
4392 STATIC_OVL boolean
generate_way_out_method(nx,ny,ov)4393 generate_way_out_method(nx,ny, ov)
4394 int nx,ny;
4395 struct opvar *ov;
4396 {
4397 static const char nhFunc[] = "generate_way_out_method";
4398 const int escapeitems[] = { PICK_AXE,
4399 DWARVISH_MATTOCK,
4400 WAN_DIGGING,
4401 WAN_TELEPORTATION,
4402 SCR_TELEPORTATION,
4403 RIN_TELEPORTATION };
4404 struct opvar *ov2 = selection_opvar((char *) 0), *ov3;
4405 schar x, y;
4406 boolean res = TRUE;
4407
4408 selection_floodfill(ov2, nx, ny, TRUE);
4409 ov3 = opvar_clone(ov2);
4410
4411 /* try to make a secret door */
4412 while (selection_rndcoord(ov3, &x, &y, TRUE)) {
4413 if (isok(x+1, y) && !selection_getpoint(x+1, y, ov)
4414 && IS_WALL(levl[x+1][y].typ)
4415 && isok(x+2, y) && selection_getpoint(x+2, y, ov)
4416 && ACCESSIBLE(levl[x+2][y].typ)) {
4417 levl[x+1][y].typ = SDOOR;
4418 goto gotitdone;
4419 }
4420 if (isok(x-1, y) && !selection_getpoint(x-1, y, ov)
4421 && IS_WALL(levl[x-1][y].typ)
4422 && isok(x-2, y) && selection_getpoint(x-2, y, ov)
4423 && ACCESSIBLE(levl[x-2][y].typ)) {
4424 levl[x-1][y].typ = SDOOR;
4425 goto gotitdone;
4426 }
4427 if (isok(x, y+1) && !selection_getpoint(x, y+1, ov)
4428 && IS_WALL(levl[x][y+1].typ)
4429 && isok(x, y+2) && selection_getpoint(x, y+2, ov)
4430 && ACCESSIBLE(levl[x][y+2].typ)) {
4431 levl[x][y+1].typ = SDOOR;
4432 goto gotitdone;
4433 }
4434 if (isok(x, y-1) && !selection_getpoint(x, y-1, ov)
4435 && IS_WALL(levl[x][y-1].typ)
4436 && isok(x, y-2) && selection_getpoint(x, y-2, ov)
4437 && ACCESSIBLE(levl[x][y-2].typ)) {
4438 levl[x][y-1].typ = SDOOR;
4439 goto gotitdone;
4440 }
4441 }
4442
4443 /* try to make a hole or a trapdoor */
4444 if (Can_fall_thru(&u.uz)) {
4445 opvar_free(ov3);
4446 ov3 = opvar_clone(ov2);
4447 while (selection_rndcoord(ov3, &x, &y, TRUE)) {
4448 if (maketrap(x,y, rn2(2) ? HOLE : TRAPDOOR))
4449 goto gotitdone;
4450 }
4451 }
4452
4453 /* generate one of the escape items */
4454 if (selection_rndcoord(ov2, &x, &y, FALSE)) {
4455 mksobj_at(escapeitems[rn2(SIZE(escapeitems))], x, y, TRUE, FALSE);
4456 goto gotitdone;
4457 }
4458
4459 res = FALSE;
4460 gotitdone:
4461 opvar_free(ov2);
4462 opvar_free(ov3);
4463 return res;
4464 }
4465
4466 STATIC_OVL void
ensure_way_out()4467 ensure_way_out()
4468 {
4469 static const char nhFunc[] = "ensure_way_out";
4470 struct opvar *ov = selection_opvar((char *) 0);
4471 struct trap *ttmp = ftrap;
4472 int x,y;
4473 boolean ret = TRUE;
4474
4475 set_selection_floodfillchk(floodfillchk_match_accessible);
4476
4477 if (xupstair && !selection_getpoint(xupstair, yupstair, ov))
4478 selection_floodfill(ov, xupstair, yupstair, TRUE);
4479 if (xdnstair && !selection_getpoint(xdnstair, ydnstair, ov))
4480 selection_floodfill(ov, xdnstair, ydnstair, TRUE);
4481 if (xupladder && !selection_getpoint(xupladder, yupladder, ov))
4482 selection_floodfill(ov, xupladder, yupladder, TRUE);
4483 if (xdnladder && !selection_getpoint(xdnladder, ydnladder, ov))
4484 selection_floodfill(ov, xdnladder, ydnladder, TRUE);
4485
4486 while (ttmp) {
4487 if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE
4488 || is_hole(ttmp->ttyp))
4489 && !selection_getpoint(ttmp->tx, ttmp->ty, ov))
4490 selection_floodfill(ov, ttmp->tx, ttmp->ty, TRUE);
4491 ttmp = ttmp->ntrap;
4492 }
4493
4494 do {
4495 ret = TRUE;
4496 for (x = 0; x < COLNO; x++)
4497 for (y = 0; y < ROWNO; y++)
4498 if (ACCESSIBLE(levl[x][y].typ)
4499 && !selection_getpoint(x, y, ov)) {
4500 if (generate_way_out_method(x,y, ov))
4501 selection_floodfill(ov, x,y, TRUE);
4502 ret = FALSE;
4503 goto outhere;
4504 }
4505 outhere: ;
4506 } while (!ret);
4507 opvar_free(ov);
4508 }
4509
4510 void
spo_levregion(coder)4511 spo_levregion(coder)
4512 struct sp_coder *coder;
4513 {
4514 static const char nhFunc[] = "spo_levregion";
4515 struct opvar *rname, *padding, *rtype, *del_islev, *dy2, *dx2, *dy1, *dx1,
4516 *in_islev, *iy2, *ix2, *iy1, *ix1;
4517
4518 lev_region *tmplregion;
4519
4520 if (!OV_pop_s(rname) || !OV_pop_i(padding) || !OV_pop_i(rtype)
4521 || !OV_pop_i(del_islev) || !OV_pop_i(dy2) || !OV_pop_i(dx2)
4522 || !OV_pop_i(dy1) || !OV_pop_i(dx1) || !OV_pop_i(in_islev)
4523 || !OV_pop_i(iy2) || !OV_pop_i(ix2) || !OV_pop_i(iy1)
4524 || !OV_pop_i(ix1))
4525 return;
4526
4527 tmplregion = (lev_region *) alloc(sizeof(lev_region));
4528
4529 tmplregion->inarea.x1 = OV_i(ix1);
4530 tmplregion->inarea.y1 = OV_i(iy1);
4531 tmplregion->inarea.x2 = OV_i(ix2);
4532 tmplregion->inarea.y2 = OV_i(iy2);
4533
4534 tmplregion->delarea.x1 = OV_i(dx1);
4535 tmplregion->delarea.y1 = OV_i(dy1);
4536 tmplregion->delarea.x2 = OV_i(dx2);
4537 tmplregion->delarea.y2 = OV_i(dy2);
4538
4539 tmplregion->in_islev = OV_i(in_islev);
4540 tmplregion->del_islev = OV_i(del_islev);
4541 tmplregion->rtype = OV_i(rtype);
4542 tmplregion->padding = OV_i(padding);
4543 tmplregion->rname.str = dupstr(OV_s(rname));
4544
4545 if (!tmplregion->in_islev) {
4546 get_location(&tmplregion->inarea.x1, &tmplregion->inarea.y1, ANY_LOC,
4547 (struct mkroom *) 0);
4548 get_location(&tmplregion->inarea.x2, &tmplregion->inarea.y2, ANY_LOC,
4549 (struct mkroom *) 0);
4550 }
4551
4552 if (!tmplregion->del_islev) {
4553 get_location(&tmplregion->delarea.x1, &tmplregion->delarea.y1,
4554 ANY_LOC, (struct mkroom *) 0);
4555 get_location(&tmplregion->delarea.x2, &tmplregion->delarea.y2,
4556 ANY_LOC, (struct mkroom *) 0);
4557 }
4558 if (num_lregions) {
4559 /* realloc the lregion space to add the new one */
4560 lev_region *newl = (lev_region *) alloc(
4561 sizeof(lev_region) * (unsigned) (1 + num_lregions));
4562
4563 (void) memcpy((genericptr_t) (newl), (genericptr_t) lregions,
4564 sizeof(lev_region) * num_lregions);
4565 Free(lregions);
4566 num_lregions++;
4567 lregions = newl;
4568 } else {
4569 num_lregions = 1;
4570 lregions = (lev_region *) alloc(sizeof(lev_region));
4571 }
4572 (void) memcpy(&lregions[num_lregions - 1], tmplregion,
4573 sizeof(lev_region));
4574 free(tmplregion);
4575
4576 opvar_free(dx1);
4577 opvar_free(dy1);
4578 opvar_free(dx2);
4579 opvar_free(dy2);
4580
4581 opvar_free(ix1);
4582 opvar_free(iy1);
4583 opvar_free(ix2);
4584 opvar_free(iy2);
4585
4586 opvar_free(del_islev);
4587 opvar_free(in_islev);
4588 opvar_free(rname);
4589 opvar_free(rtype);
4590 opvar_free(padding);
4591 }
4592
4593 void
spo_region(coder)4594 spo_region(coder)
4595 struct sp_coder *coder;
4596 {
4597 static const char nhFunc[] = "spo_region";
4598 struct opvar *rtype, *rlit, *rflags, *area;
4599 xchar dx1, dy1, dx2, dy2;
4600 register struct mkroom *troom;
4601 boolean prefilled, room_not_needed, irregular, joined;
4602
4603 if (!OV_pop_i(rflags) || !OV_pop_i(rtype) || !OV_pop_i(rlit)
4604 || !OV_pop_r(area))
4605 return;
4606
4607 prefilled = !(OV_i(rflags) & (1 << 0));
4608 irregular = (OV_i(rflags) & (1 << 1));
4609 joined = !(OV_i(rflags) & (1 << 2));
4610
4611 if (OV_i(rtype) > MAXRTYPE) {
4612 OV_i(rtype) -= MAXRTYPE + 1;
4613 prefilled = TRUE;
4614 } else
4615 prefilled = FALSE;
4616
4617 if (OV_i(rlit) < 0)
4618 OV_i(rlit) =
4619 (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
4620
4621 dx1 = SP_REGION_X1(OV_i(area));
4622 dy1 = SP_REGION_Y1(OV_i(area));
4623 dx2 = SP_REGION_X2(OV_i(area));
4624 dy2 = SP_REGION_Y2(OV_i(area));
4625
4626 get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0);
4627 get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0);
4628
4629 /* for an ordinary room, `prefilled' is a flag to force
4630 an actual room to be created (such rooms are used to
4631 control placement of migrating monster arrivals) */
4632 room_not_needed = (OV_i(rtype) == OROOM && !irregular && !prefilled);
4633 if (room_not_needed || nroom >= MAXNROFROOMS) {
4634 region tmpregion;
4635 if (!room_not_needed)
4636 impossible("Too many rooms on new level!");
4637 tmpregion.rlit = OV_i(rlit);
4638 tmpregion.x1 = dx1;
4639 tmpregion.y1 = dy1;
4640 tmpregion.x2 = dx2;
4641 tmpregion.y2 = dy2;
4642 light_region(&tmpregion);
4643
4644 opvar_free(area);
4645 opvar_free(rflags);
4646 opvar_free(rlit);
4647 opvar_free(rtype);
4648
4649 return;
4650 }
4651
4652 troom = &rooms[nroom];
4653
4654 /* mark rooms that must be filled, but do it later */
4655 if (OV_i(rtype) != OROOM)
4656 troom->needfill = (prefilled ? 2 : 1);
4657
4658 troom->needjoining = joined;
4659
4660 if (irregular) {
4661 min_rx = max_rx = dx1;
4662 min_ry = max_ry = dy1;
4663 smeq[nroom] = nroom;
4664 flood_fill_rm(dx1, dy1, nroom + ROOMOFFSET, OV_i(rlit), TRUE);
4665 add_room(min_rx, min_ry, max_rx, max_ry, FALSE, OV_i(rtype), TRUE);
4666 troom->rlit = OV_i(rlit);
4667 troom->irregular = TRUE;
4668 } else {
4669 add_room(dx1, dy1, dx2, dy2, OV_i(rlit), OV_i(rtype), TRUE);
4670 #ifdef SPECIALIZATION
4671 topologize(troom, FALSE); /* set roomno */
4672 #else
4673 topologize(troom); /* set roomno */
4674 #endif
4675 }
4676
4677 if (!room_not_needed) {
4678 if (coder->n_subroom > 1)
4679 impossible("region as subroom");
4680 else {
4681 coder->tmproomlist[coder->n_subroom] = troom;
4682 coder->failed_room[coder->n_subroom] = FALSE;
4683 coder->n_subroom++;
4684 }
4685 }
4686
4687 opvar_free(area);
4688 opvar_free(rflags);
4689 opvar_free(rlit);
4690 opvar_free(rtype);
4691 }
4692
4693 void
spo_drawbridge(coder)4694 spo_drawbridge(coder)
4695 struct sp_coder *coder;
4696 {
4697 static const char nhFunc[] = "spo_drawbridge";
4698 xchar x, y;
4699 int dopen;
4700 struct opvar *dir, *db_open, *dcoord;
4701
4702 if (!OV_pop_i(dir) || !OV_pop_i(db_open) || !OV_pop_c(dcoord))
4703 return;
4704
4705 get_location_coord(&x, &y, DRY | WET | HOT, coder->croom, OV_i(dcoord));
4706 if ((dopen = OV_i(db_open)) == -1)
4707 dopen = !rn2(2);
4708 if (!create_drawbridge(x, y, OV_i(dir), dopen ? TRUE : FALSE))
4709 impossible("Cannot create drawbridge.");
4710 SpLev_Map[x][y] = 1;
4711
4712 opvar_free(dcoord);
4713 opvar_free(db_open);
4714 opvar_free(dir);
4715 }
4716
4717 void
spo_mazewalk(coder)4718 spo_mazewalk(coder)
4719 struct sp_coder *coder;
4720 {
4721 static const char nhFunc[] = "spo_mazewalk";
4722 xchar x, y;
4723 struct opvar *ftyp, *fstocked, *fdir, *mcoord;
4724 int dir;
4725
4726 if (!OV_pop_i(ftyp) || !OV_pop_i(fstocked) || !OV_pop_i(fdir)
4727 || !OV_pop_c(mcoord))
4728 return;
4729
4730 dir = OV_i(fdir);
4731
4732 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(mcoord));
4733 if (!isok(x, y))
4734 return;
4735
4736 if (OV_i(ftyp) < 1) {
4737 OV_i(ftyp) = level.flags.corrmaze ? CORR : ROOM;
4738 }
4739
4740 /* don't use move() - it doesn't use W_NORTH, etc. */
4741 switch (dir) {
4742 case W_NORTH:
4743 --y;
4744 break;
4745 case W_SOUTH:
4746 y++;
4747 break;
4748 case W_EAST:
4749 x++;
4750 break;
4751 case W_WEST:
4752 --x;
4753 break;
4754 default:
4755 impossible("spo_mazewalk: Bad MAZEWALK direction");
4756 }
4757
4758 if (!IS_DOOR(levl[x][y].typ)) {
4759 levl[x][y].typ = OV_i(ftyp);
4760 levl[x][y].flags = 0;
4761 }
4762
4763 /*
4764 * We must be sure that the parity of the coordinates for
4765 * walkfrom() is odd. But we must also take into account
4766 * what direction was chosen.
4767 */
4768 if (!(x % 2)) {
4769 if (dir == W_EAST)
4770 x++;
4771 else
4772 x--;
4773
4774 /* no need for IS_DOOR check; out of map bounds */
4775 levl[x][y].typ = OV_i(ftyp);
4776 levl[x][y].flags = 0;
4777 }
4778
4779 if (!(y % 2)) {
4780 if (dir == W_SOUTH)
4781 y++;
4782 else
4783 y--;
4784 }
4785
4786 walkfrom(x, y, OV_i(ftyp));
4787 if (OV_i(fstocked))
4788 fill_empty_maze();
4789
4790 opvar_free(mcoord);
4791 opvar_free(fdir);
4792 opvar_free(fstocked);
4793 opvar_free(ftyp);
4794 }
4795
4796 void
spo_wall_property(coder)4797 spo_wall_property(coder)
4798 struct sp_coder *coder;
4799 {
4800 static const char nhFunc[] = "spo_wall_property";
4801 struct opvar *r;
4802 xchar dx1, dy1, dx2, dy2;
4803 int wprop = (coder->opcode == SPO_NON_DIGGABLE)
4804 ? W_NONDIGGABLE
4805 : W_NONPASSWALL;
4806
4807 if (!OV_pop_r(r))
4808 return;
4809
4810 dx1 = SP_REGION_X1(OV_i(r));
4811 dy1 = SP_REGION_Y1(OV_i(r));
4812 dx2 = SP_REGION_X2(OV_i(r));
4813 dy2 = SP_REGION_Y2(OV_i(r));
4814
4815 get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0);
4816 get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0);
4817
4818 set_wall_property(dx1, dy1, dx2, dy2, wprop);
4819
4820 opvar_free(r);
4821 }
4822
4823 void
spo_room_door(coder)4824 spo_room_door(coder)
4825 struct sp_coder *coder;
4826 {
4827 static const char nhFunc[] = "spo_room_door";
4828 struct opvar *wall, *secret, *mask, *pos;
4829 room_door tmpd;
4830
4831 if (!OV_pop_i(wall) || !OV_pop_i(secret) || !OV_pop_i(mask)
4832 || !OV_pop_i(pos) || !coder->croom)
4833 return;
4834
4835 tmpd.secret = OV_i(secret);
4836 tmpd.mask = OV_i(mask);
4837 tmpd.pos = OV_i(pos);
4838 tmpd.wall = OV_i(wall);
4839
4840 create_door(&tmpd, coder->croom);
4841
4842 opvar_free(wall);
4843 opvar_free(secret);
4844 opvar_free(mask);
4845 opvar_free(pos);
4846 }
4847
4848 /*ARGSUSED*/
4849 void
sel_set_wallify(x,y,arg)4850 sel_set_wallify(x, y, arg)
4851 int x, y;
4852 genericptr_t arg UNUSED;
4853 {
4854 wallify_map(x, y, x, y);
4855 }
4856
4857 void
spo_wallify(coder)4858 spo_wallify(coder)
4859 struct sp_coder *coder;
4860 {
4861 static const char nhFunc[] = "spo_wallify";
4862 struct opvar *typ, *r;
4863 int dx1, dy1, dx2, dy2;
4864
4865 if (!OV_pop_i(typ))
4866 return;
4867 switch (OV_i(typ)) {
4868 default:
4869 case 0:
4870 if (!OV_pop_r(r))
4871 return;
4872 dx1 = (xchar) SP_REGION_X1(OV_i(r));
4873 dy1 = (xchar) SP_REGION_Y1(OV_i(r));
4874 dx2 = (xchar) SP_REGION_X2(OV_i(r));
4875 dy2 = (xchar) SP_REGION_Y2(OV_i(r));
4876 wallify_map(dx1 < 0 ? (xstart - 1) : dx1,
4877 dy1 < 0 ? (ystart - 1) : dy1,
4878 dx2 < 0 ? (xstart + xsize + 1) : dx2,
4879 dy2 < 0 ? (ystart + ysize + 1) : dy2);
4880 break;
4881 case 1:
4882 if (!OV_pop_typ(r, SPOVAR_SEL))
4883 return;
4884 selection_iterate(r, sel_set_wallify, NULL);
4885 break;
4886 }
4887 opvar_free(r);
4888 opvar_free(typ);
4889 }
4890
4891 void
spo_map(coder)4892 spo_map(coder)
4893 struct sp_coder *coder;
4894 {
4895 static const char nhFunc[] = "spo_map";
4896 mazepart tmpmazepart;
4897 struct opvar *mpxs, *mpys, *mpmap, *mpa, *mpkeepr, *mpzalign;
4898 xchar halign, valign;
4899 xchar tmpxstart, tmpystart, tmpxsize, tmpysize;
4900 unpacked_coord upc;
4901
4902 if (!OV_pop_i(mpxs) || !OV_pop_i(mpys) || !OV_pop_s(mpmap)
4903 || !OV_pop_i(mpkeepr) || !OV_pop_i(mpzalign) || !OV_pop_c(mpa))
4904 return;
4905
4906 tmpmazepart.xsize = OV_i(mpxs);
4907 tmpmazepart.ysize = OV_i(mpys);
4908 tmpmazepart.zaligntyp = OV_i(mpzalign);
4909
4910 upc = get_unpacked_coord(OV_i(mpa), ANY_LOC);
4911 tmpmazepart.halign = upc.x;
4912 tmpmazepart.valign = upc.y;
4913
4914 tmpxsize = xsize;
4915 tmpysize = ysize;
4916 tmpxstart = xstart;
4917 tmpystart = ystart;
4918
4919 halign = tmpmazepart.halign;
4920 valign = tmpmazepart.valign;
4921 xsize = tmpmazepart.xsize;
4922 ysize = tmpmazepart.ysize;
4923 switch (tmpmazepart.zaligntyp) {
4924 default:
4925 case 0:
4926 break;
4927 case 1:
4928 switch ((int) halign) {
4929 case LEFT:
4930 xstart = splev_init_present ? 1 : 3;
4931 break;
4932 case H_LEFT:
4933 xstart = 2 + ((x_maze_max - 2 - xsize) / 4);
4934 break;
4935 case CENTER:
4936 xstart = 2 + ((x_maze_max - 2 - xsize) / 2);
4937 break;
4938 case H_RIGHT:
4939 xstart = 2 + ((x_maze_max - 2 - xsize) * 3 / 4);
4940 break;
4941 case RIGHT:
4942 xstart = x_maze_max - xsize - 1;
4943 break;
4944 }
4945 switch ((int) valign) {
4946 case TOP:
4947 ystart = 3;
4948 break;
4949 case CENTER:
4950 ystart = 2 + ((y_maze_max - 2 - ysize) / 2);
4951 break;
4952 case BOTTOM:
4953 ystart = y_maze_max - ysize - 1;
4954 break;
4955 }
4956 if (!(xstart % 2))
4957 xstart++;
4958 if (!(ystart % 2))
4959 ystart++;
4960 break;
4961 case 2:
4962 if (!coder->croom) {
4963 xstart = 1;
4964 ystart = 0;
4965 xsize = COLNO - 1 - tmpmazepart.xsize;
4966 ysize = ROWNO - tmpmazepart.ysize;
4967 }
4968 get_location_coord(&halign, &valign, ANY_LOC, coder->croom,
4969 OV_i(mpa));
4970 xsize = tmpmazepart.xsize;
4971 ysize = tmpmazepart.ysize;
4972 xstart = halign;
4973 ystart = valign;
4974 break;
4975 }
4976 if (ystart < 0 || ystart + ysize > ROWNO) {
4977 /* try to move the start a bit */
4978 ystart += (ystart > 0) ? -2 : 2;
4979 if (ysize == ROWNO)
4980 ystart = 0;
4981 if (ystart < 0 || ystart + ysize > ROWNO)
4982 panic("reading special level with ysize too large");
4983 }
4984 if (xsize <= 1 && ysize <= 1) {
4985 xstart = 1;
4986 ystart = 0;
4987 xsize = COLNO - 1;
4988 ysize = ROWNO;
4989 } else {
4990 xchar x, y, mptyp;
4991
4992 /* Load the map */
4993 for (y = ystart; y < ystart + ysize; y++)
4994 for (x = xstart; x < xstart + xsize; x++) {
4995 mptyp = (mpmap->vardata.str[(y - ystart) * xsize
4996 + (x - xstart)] - 1);
4997 if (mptyp >= MAX_TYPE)
4998 continue;
4999 levl[x][y].typ = mptyp;
5000 levl[x][y].lit = FALSE;
5001 /* clear out levl: load_common_data may set them */
5002 levl[x][y].flags = 0;
5003 levl[x][y].horizontal = 0;
5004 levl[x][y].roomno = 0;
5005 levl[x][y].edge = 0;
5006 SpLev_Map[x][y] = 1;
5007 /*
5008 * Set secret doors to closed (why not trapped too?). Set
5009 * the horizontal bit.
5010 */
5011 if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
5012 if (levl[x][y].typ == SDOOR)
5013 levl[x][y].doormask = D_CLOSED;
5014 /*
5015 * If there is a wall to the left that connects to a
5016 * (secret) door, then it is horizontal. This does
5017 * not allow (secret) doors to be corners of rooms.
5018 */
5019 if (x != xstart && (IS_WALL(levl[x - 1][y].typ)
5020 || levl[x - 1][y].horizontal))
5021 levl[x][y].horizontal = 1;
5022 } else if (levl[x][y].typ == HWALL
5023 || levl[x][y].typ == IRONBARS)
5024 levl[x][y].horizontal = 1;
5025 else if (levl[x][y].typ == LAVAPOOL)
5026 levl[x][y].lit = 1;
5027 else if (splev_init_present && levl[x][y].typ == ICE)
5028 levl[x][y].icedpool = icedpools ? ICED_POOL : ICED_MOAT;
5029 }
5030 if (coder->lvl_is_joined)
5031 remove_rooms(xstart, ystart, xstart + xsize, ystart + ysize);
5032 }
5033 if (!OV_i(mpkeepr)) {
5034 xstart = tmpxstart;
5035 ystart = tmpystart;
5036 xsize = tmpxsize;
5037 ysize = tmpysize;
5038 }
5039
5040 opvar_free(mpxs);
5041 opvar_free(mpys);
5042 opvar_free(mpmap);
5043 opvar_free(mpa);
5044 opvar_free(mpkeepr);
5045 opvar_free(mpzalign);
5046 }
5047
5048 void
spo_jmp(coder,lvl)5049 spo_jmp(coder, lvl)
5050 struct sp_coder *coder;
5051 sp_lev *lvl;
5052 {
5053 static const char nhFunc[] = "spo_jmp";
5054 struct opvar *tmpa;
5055 long a;
5056
5057 if (!OV_pop_i(tmpa))
5058 return;
5059 a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(tmpa) - 1));
5060 if ((a >= 0) && (a < lvl->n_opcodes) && (a != coder->frame->n_opcode))
5061 coder->frame->n_opcode = a;
5062 opvar_free(tmpa);
5063 }
5064
5065 void
spo_conditional_jump(coder,lvl)5066 spo_conditional_jump(coder, lvl)
5067 struct sp_coder *coder;
5068 sp_lev *lvl;
5069 {
5070 static const char nhFunc[] = "spo_conditional_jump";
5071 struct opvar *oa, *oc;
5072 long a, c;
5073 int test = 0;
5074
5075 if (!OV_pop_i(oa) || !OV_pop_i(oc))
5076 return;
5077
5078 a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(oa) - 1));
5079 c = OV_i(oc);
5080
5081 switch (coder->opcode) {
5082 default:
5083 impossible("spo_conditional_jump: illegal opcode");
5084 break;
5085 case SPO_JL:
5086 test = (c & SP_CPUFLAG_LT);
5087 break;
5088 case SPO_JLE:
5089 test = (c & (SP_CPUFLAG_LT | SP_CPUFLAG_EQ));
5090 break;
5091 case SPO_JG:
5092 test = (c & SP_CPUFLAG_GT);
5093 break;
5094 case SPO_JGE:
5095 test = (c & (SP_CPUFLAG_GT | SP_CPUFLAG_EQ));
5096 break;
5097 case SPO_JE:
5098 test = (c & SP_CPUFLAG_EQ);
5099 break;
5100 case SPO_JNE:
5101 test = (c & ~SP_CPUFLAG_EQ);
5102 break;
5103 }
5104
5105 if ((test) && (a >= 0) && (a < lvl->n_opcodes)
5106 && (a != coder->frame->n_opcode))
5107 coder->frame->n_opcode = a;
5108
5109 opvar_free(oa);
5110 opvar_free(oc);
5111 }
5112
5113 void
spo_var_init(coder)5114 spo_var_init(coder)
5115 struct sp_coder *coder;
5116 {
5117 static const char nhFunc[] = "spo_var_init";
5118 struct opvar *vname;
5119 struct opvar *arraylen;
5120 struct opvar *vvalue;
5121 struct splev_var *tmpvar;
5122 struct splev_var *tmp2;
5123 long idx;
5124
5125 OV_pop_s(vname);
5126 OV_pop_i(arraylen);
5127
5128 if (!vname || !arraylen)
5129 panic("no values for SPO_VAR_INIT");
5130
5131 tmpvar = opvar_var_defined(coder, OV_s(vname));
5132
5133 if (tmpvar) {
5134 /* variable redefinition */
5135 if (OV_i(arraylen) < 0) {
5136 /* copy variable */
5137 if (tmpvar->array_len) {
5138 idx = tmpvar->array_len;
5139 while (idx-- > 0) {
5140 opvar_free(tmpvar->data.arrayvalues[idx]);
5141 }
5142 Free(tmpvar->data.arrayvalues);
5143 } else {
5144 opvar_free(tmpvar->data.value);
5145 }
5146 tmpvar->data.arrayvalues = NULL;
5147 goto copy_variable;
5148 } else if (OV_i(arraylen)) {
5149 /* redefined array */
5150 idx = tmpvar->array_len;
5151 while (idx-- > 0) {
5152 opvar_free(tmpvar->data.arrayvalues[idx]);
5153 }
5154 Free(tmpvar->data.arrayvalues);
5155 tmpvar->data.arrayvalues = NULL;
5156 goto create_new_array;
5157 } else {
5158 /* redefined single value */
5159 OV_pop(vvalue);
5160 if (tmpvar->svtyp != vvalue->spovartyp)
5161 panic("redefining variable as different type");
5162 opvar_free(tmpvar->data.value);
5163 tmpvar->data.value = vvalue;
5164 tmpvar->array_len = 0;
5165 }
5166 } else {
5167 /* new variable definition */
5168 tmpvar = (struct splev_var *) alloc(sizeof(struct splev_var));
5169 tmpvar->next = coder->frame->variables;
5170 tmpvar->name = dupstr(OV_s(vname));
5171 coder->frame->variables = tmpvar;
5172
5173 if (OV_i(arraylen) < 0) {
5174 /* copy variable */
5175 copy_variable:
5176 OV_pop(vvalue);
5177 tmp2 = opvar_var_defined(coder, OV_s(vvalue));
5178 if (!tmp2)
5179 panic("no copyable var");
5180 tmpvar->svtyp = tmp2->svtyp;
5181 tmpvar->array_len = tmp2->array_len;
5182 if (tmpvar->array_len) {
5183 idx = tmpvar->array_len;
5184 tmpvar->data.arrayvalues =
5185 (struct opvar **) alloc(sizeof(struct opvar *) * idx);
5186 while (idx-- > 0) {
5187 tmpvar->data.arrayvalues[idx] =
5188 opvar_clone(tmp2->data.arrayvalues[idx]);
5189 }
5190 } else {
5191 tmpvar->data.value = opvar_clone(tmp2->data.value);
5192 }
5193 opvar_free(vvalue);
5194 } else if (OV_i(arraylen)) {
5195 /* new array */
5196 create_new_array:
5197 idx = OV_i(arraylen);
5198 tmpvar->array_len = idx;
5199 tmpvar->data.arrayvalues =
5200 (struct opvar **) alloc(sizeof(struct opvar *) * idx);
5201 while (idx-- > 0) {
5202 OV_pop(vvalue);
5203 if (!vvalue)
5204 panic("no value for arrayvariable");
5205 tmpvar->data.arrayvalues[idx] = vvalue;
5206 }
5207 tmpvar->svtyp = SPOVAR_ARRAY;
5208 } else {
5209 /* new single value */
5210 OV_pop(vvalue);
5211 if (!vvalue)
5212 panic("no value for variable");
5213 tmpvar->svtyp = OV_typ(vvalue);
5214 tmpvar->data.value = vvalue;
5215 tmpvar->array_len = 0;
5216 }
5217 }
5218
5219 opvar_free(vname);
5220 opvar_free(arraylen);
5221
5222 }
5223
5224 #if 0
5225 STATIC_OVL long
5226 opvar_array_length(coder)
5227 struct sp_coder *coder;
5228 {
5229 static const char nhFunc[] = "opvar_array_length";
5230 struct opvar *vname;
5231 struct splev_var *tmp;
5232 long len = 0;
5233
5234 if (!coder)
5235 return 0;
5236
5237 vname = splev_stack_pop(coder->stack);
5238 if (!vname)
5239 return 0;
5240 if (vname->spovartyp != SPOVAR_VARIABLE)
5241 goto pass;
5242
5243 tmp = coder->frame->variables;
5244 while (tmp) {
5245 if (!strcmp(tmp->name, OV_s(vname))) {
5246 if ((tmp->svtyp & SPOVAR_ARRAY)) {
5247 len = tmp->array_len;
5248 if (len < 1)
5249 len = 0;
5250 }
5251 goto pass;
5252 }
5253 tmp = tmp->next;
5254 }
5255
5256 pass:
5257 opvar_free(vname);
5258 return len;
5259 }
5260 #endif /*0*/
5261
5262 void
spo_shuffle_array(coder)5263 spo_shuffle_array(coder)
5264 struct sp_coder *coder;
5265 {
5266 static const char nhFunc[] = "spo_shuffle_array";
5267 struct opvar *vname;
5268 struct splev_var *tmp;
5269 struct opvar *tmp2;
5270 long i, j;
5271
5272 if (!OV_pop_s(vname))
5273 return;
5274
5275 tmp = opvar_var_defined(coder, OV_s(vname));
5276 if (!tmp || (tmp->array_len < 1)) {
5277 opvar_free(vname);
5278 return;
5279 }
5280 for (i = tmp->array_len - 1; i > 0; i--) {
5281 if ((j = rn2(i + 1)) == i)
5282 continue;
5283 tmp2 = tmp->data.arrayvalues[j];
5284 tmp->data.arrayvalues[j] = tmp->data.arrayvalues[i];
5285 tmp->data.arrayvalues[i] = tmp2;
5286 }
5287
5288 opvar_free(vname);
5289 }
5290
5291 /* Special level coder, creates the special level from the sp_lev codes.
5292 * Does not free the allocated memory.
5293 */
5294 STATIC_OVL boolean
sp_level_coder(lvl)5295 sp_level_coder(lvl)
5296 sp_lev *lvl;
5297 {
5298 static const char nhFunc[] = "sp_level_coder";
5299 unsigned long exec_opcodes = 0;
5300 int tmpi;
5301 long room_stack = 0;
5302 unsigned long max_execution = SPCODER_MAX_RUNTIME;
5303 struct sp_coder *coder =
5304 (struct sp_coder *) alloc(sizeof (struct sp_coder));
5305
5306 coder->frame = frame_new(0);
5307 coder->stack = NULL;
5308 coder->premapped = FALSE;
5309 coder->solidify = FALSE;
5310 coder->check_inaccessibles = FALSE;
5311 coder->croom = NULL;
5312 coder->n_subroom = 1;
5313 coder->exit_script = FALSE;
5314 coder->lvl_is_joined = 0;
5315
5316 splev_init_present = FALSE;
5317 icedpools = FALSE;
5318 /* achievement tracking; static init would suffice except we need to
5319 reset if #wizmakemap is used to recreate mines' end or sokoban end;
5320 once either level is created, these values can be forgotten */
5321 mines_prize_count = soko_prize_count = 0;
5322
5323 if (wizard) {
5324 char *met = nh_getenv("SPCODER_MAX_RUNTIME");
5325
5326 if (met && met[0] == '1')
5327 max_execution = (1 << 30) - 1;
5328 }
5329
5330 for (tmpi = 0; tmpi <= MAX_NESTED_ROOMS; tmpi++) {
5331 coder->tmproomlist[tmpi] = (struct mkroom *) 0;
5332 coder->failed_room[tmpi] = FALSE;
5333 }
5334
5335 shuffle_alignments();
5336
5337 for (tmpi = 0; tmpi < MAX_CONTAINMENT; tmpi++)
5338 container_obj[tmpi] = NULL;
5339 container_idx = 0;
5340
5341 invent_carrying_monster = NULL;
5342
5343 (void) memset((genericptr_t) &SpLev_Map[0][0], 0, sizeof SpLev_Map);
5344
5345 level.flags.is_maze_lev = 0;
5346
5347 xstart = 1;
5348 ystart = 0;
5349 xsize = COLNO - 1;
5350 ysize = ROWNO;
5351
5352 while (coder->frame->n_opcode < lvl->n_opcodes && !coder->exit_script) {
5353 coder->opcode = lvl->opcodes[coder->frame->n_opcode].opcode;
5354 coder->opdat = lvl->opcodes[coder->frame->n_opcode].opdat;
5355
5356 coder->stack = coder->frame->stack;
5357
5358 if (exec_opcodes++ > max_execution) {
5359 impossible("Level script is taking too much time, stopping.");
5360 coder->exit_script = TRUE;
5361 }
5362
5363 if (coder->failed_room[coder->n_subroom - 1]
5364 && coder->opcode != SPO_ENDROOM && coder->opcode != SPO_ROOM
5365 && coder->opcode != SPO_SUBROOM)
5366 goto next_opcode;
5367
5368 coder->croom = coder->tmproomlist[coder->n_subroom - 1];
5369
5370 switch (coder->opcode) {
5371 case SPO_NULL:
5372 break;
5373 case SPO_EXIT:
5374 coder->exit_script = TRUE;
5375 break;
5376 case SPO_FRAME_PUSH:
5377 spo_frame_push(coder);
5378 break;
5379 case SPO_FRAME_POP:
5380 spo_frame_pop(coder);
5381 break;
5382 case SPO_CALL:
5383 spo_call(coder);
5384 break;
5385 case SPO_RETURN:
5386 spo_return(coder);
5387 break;
5388 case SPO_END_MONINVENT:
5389 spo_end_moninvent(coder);
5390 break;
5391 case SPO_POP_CONTAINER:
5392 spo_pop_container(coder);
5393 break;
5394 case SPO_POP: {
5395 struct opvar *ov = splev_stack_pop(coder->stack);
5396
5397 opvar_free(ov);
5398 break;
5399 }
5400 case SPO_PUSH:
5401 splev_stack_push(coder->stack, opvar_clone(coder->opdat));
5402 break;
5403 case SPO_MESSAGE:
5404 spo_message(coder);
5405 break;
5406 case SPO_MONSTER:
5407 spo_monster(coder);
5408 break;
5409 case SPO_OBJECT:
5410 spo_object(coder);
5411 break;
5412 case SPO_LEVEL_FLAGS:
5413 spo_level_flags(coder);
5414 break;
5415 case SPO_INITLEVEL:
5416 spo_initlevel(coder);
5417 break;
5418 case SPO_ENGRAVING:
5419 spo_engraving(coder);
5420 break;
5421 case SPO_MINERALIZE:
5422 spo_mineralize(coder);
5423 break;
5424 case SPO_SUBROOM:
5425 case SPO_ROOM:
5426 if (!coder->failed_room[coder->n_subroom - 1]) {
5427 spo_room(coder);
5428 } else
5429 room_stack++;
5430 break;
5431 case SPO_ENDROOM:
5432 if (coder->failed_room[coder->n_subroom - 1]) {
5433 if (!room_stack)
5434 spo_endroom(coder);
5435 else
5436 room_stack--;
5437 } else {
5438 spo_endroom(coder);
5439 }
5440 break;
5441 case SPO_DOOR:
5442 spo_door(coder);
5443 break;
5444 case SPO_STAIR:
5445 spo_stair(coder);
5446 break;
5447 case SPO_LADDER:
5448 spo_ladder(coder);
5449 break;
5450 case SPO_GRAVE:
5451 spo_grave(coder);
5452 break;
5453 case SPO_ALTAR:
5454 spo_altar(coder);
5455 break;
5456 case SPO_SINK:
5457 case SPO_POOL:
5458 case SPO_FOUNTAIN:
5459 spo_feature(coder);
5460 break;
5461 case SPO_TRAP:
5462 spo_trap(coder);
5463 break;
5464 case SPO_GOLD:
5465 spo_gold(coder);
5466 break;
5467 case SPO_CORRIDOR:
5468 spo_corridor(coder);
5469 break;
5470 case SPO_TERRAIN:
5471 spo_terrain(coder);
5472 break;
5473 case SPO_REPLACETERRAIN:
5474 spo_replace_terrain(coder);
5475 break;
5476 case SPO_LEVREGION:
5477 spo_levregion(coder);
5478 break;
5479 case SPO_REGION:
5480 spo_region(coder);
5481 break;
5482 case SPO_DRAWBRIDGE:
5483 spo_drawbridge(coder);
5484 break;
5485 case SPO_MAZEWALK:
5486 spo_mazewalk(coder);
5487 break;
5488 case SPO_NON_PASSWALL:
5489 case SPO_NON_DIGGABLE:
5490 spo_wall_property(coder);
5491 break;
5492 case SPO_ROOM_DOOR:
5493 spo_room_door(coder);
5494 break;
5495 case SPO_WALLIFY:
5496 spo_wallify(coder);
5497 break;
5498 case SPO_COPY: {
5499 struct opvar *a = splev_stack_pop(coder->stack);
5500
5501 splev_stack_push(coder->stack, opvar_clone(a));
5502 splev_stack_push(coder->stack, opvar_clone(a));
5503 opvar_free(a);
5504 break;
5505 }
5506 case SPO_DEC: {
5507 struct opvar *a;
5508
5509 if (!OV_pop_i(a))
5510 break;
5511 OV_i(a)--;
5512 splev_stack_push(coder->stack, a);
5513 break;
5514 }
5515 case SPO_INC: {
5516 struct opvar *a;
5517
5518 if (!OV_pop_i(a))
5519 break;
5520 OV_i(a)++;
5521 splev_stack_push(coder->stack, a);
5522 break;
5523 }
5524 case SPO_MATH_SIGN: {
5525 struct opvar *a;
5526
5527 if (!OV_pop_i(a))
5528 break;
5529 OV_i(a) = ((OV_i(a) < 0) ? -1 : ((OV_i(a) > 0) ? 1 : 0));
5530 splev_stack_push(coder->stack, a);
5531 break;
5532 }
5533 case SPO_MATH_ADD: {
5534 struct opvar *a, *b;
5535
5536 if (!OV_pop(b) || !OV_pop(a))
5537 break;
5538 if (OV_typ(b) == OV_typ(a)) {
5539 if (OV_typ(a) == SPOVAR_INT) {
5540 OV_i(a) = OV_i(a) + OV_i(b);
5541 splev_stack_push(coder->stack, a);
5542 opvar_free(b);
5543 } else if (OV_typ(a) == SPOVAR_STRING) {
5544 struct opvar *c;
5545 char *tmpbuf = (char *) alloc(strlen(OV_s(a))
5546 + strlen(OV_s(b)) + 1);
5547
5548 (void) sprintf(tmpbuf, "%s%s", OV_s(a), OV_s(b));
5549 c = opvar_new_str(tmpbuf);
5550 splev_stack_push(coder->stack, c);
5551 opvar_free(a);
5552 opvar_free(b);
5553 Free(tmpbuf);
5554 } else {
5555 splev_stack_push(coder->stack, a);
5556 opvar_free(b);
5557 impossible("adding weird types");
5558 }
5559 } else {
5560 splev_stack_push(coder->stack, a);
5561 opvar_free(b);
5562 impossible("adding different types");
5563 }
5564 break;
5565 }
5566 case SPO_MATH_SUB: {
5567 struct opvar *a, *b;
5568
5569 if (!OV_pop_i(b) || !OV_pop_i(a))
5570 break;
5571 OV_i(a) = OV_i(a) - OV_i(b);
5572 splev_stack_push(coder->stack, a);
5573 opvar_free(b);
5574 break;
5575 }
5576 case SPO_MATH_MUL: {
5577 struct opvar *a, *b;
5578
5579 if (!OV_pop_i(b) || !OV_pop_i(a))
5580 break;
5581 OV_i(a) = OV_i(a) * OV_i(b);
5582 splev_stack_push(coder->stack, a);
5583 opvar_free(b);
5584 break;
5585 }
5586 case SPO_MATH_DIV: {
5587 struct opvar *a, *b;
5588
5589 if (!OV_pop_i(b) || !OV_pop_i(a))
5590 break;
5591 if (OV_i(b) >= 1) {
5592 OV_i(a) = OV_i(a) / OV_i(b);
5593 } else {
5594 OV_i(a) = 0;
5595 }
5596 splev_stack_push(coder->stack, a);
5597 opvar_free(b);
5598 break;
5599 }
5600 case SPO_MATH_MOD: {
5601 struct opvar *a, *b;
5602
5603 if (!OV_pop_i(b) || !OV_pop_i(a))
5604 break;
5605 if (OV_i(b) > 0) {
5606 OV_i(a) = OV_i(a) % OV_i(b);
5607 } else {
5608 OV_i(a) = 0;
5609 }
5610 splev_stack_push(coder->stack, a);
5611 opvar_free(b);
5612 break;
5613 }
5614 case SPO_CMP: {
5615 struct opvar *a;
5616 struct opvar *b;
5617 struct opvar *c;
5618 long val = 0;
5619
5620 OV_pop(b);
5621 OV_pop(a);
5622 if (!a || !b) {
5623 impossible("spo_cmp: no values in stack");
5624 break;
5625 }
5626 if (OV_typ(a) != OV_typ(b)) {
5627 impossible("spo_cmp: trying to compare differing datatypes");
5628 break;
5629 }
5630 switch (OV_typ(a)) {
5631 case SPOVAR_COORD:
5632 case SPOVAR_REGION:
5633 case SPOVAR_MAPCHAR:
5634 case SPOVAR_MONST:
5635 case SPOVAR_OBJ:
5636 case SPOVAR_INT:
5637 if (OV_i(b) > OV_i(a))
5638 val |= SP_CPUFLAG_LT;
5639 if (OV_i(b) < OV_i(a))
5640 val |= SP_CPUFLAG_GT;
5641 if (OV_i(b) == OV_i(a))
5642 val |= SP_CPUFLAG_EQ;
5643 c = opvar_new_int(val);
5644 break;
5645 case SPOVAR_STRING:
5646 c = opvar_new_int(!strcmp(OV_s(b), OV_s(a))
5647 ? SP_CPUFLAG_EQ
5648 : 0);
5649 break;
5650 default:
5651 c = opvar_new_int(0);
5652 break;
5653 }
5654 splev_stack_push(coder->stack, c);
5655 opvar_free(a);
5656 opvar_free(b);
5657 break;
5658 }
5659 case SPO_JMP:
5660 spo_jmp(coder, lvl);
5661 break;
5662 case SPO_JL:
5663 case SPO_JLE:
5664 case SPO_JG:
5665 case SPO_JGE:
5666 case SPO_JE:
5667 case SPO_JNE:
5668 spo_conditional_jump(coder, lvl);
5669 break;
5670 case SPO_RN2: {
5671 struct opvar *tmpv;
5672 struct opvar *t;
5673
5674 if (!OV_pop_i(tmpv))
5675 break;
5676 t = opvar_new_int((OV_i(tmpv) > 1) ? rn2(OV_i(tmpv)) : 0);
5677 splev_stack_push(coder->stack, t);
5678 opvar_free(tmpv);
5679 break;
5680 }
5681 case SPO_DICE: {
5682 struct opvar *a, *b, *t;
5683
5684 if (!OV_pop_i(b) || !OV_pop_i(a))
5685 break;
5686 if (OV_i(b) < 1)
5687 OV_i(b) = 1;
5688 if (OV_i(a) < 1)
5689 OV_i(a) = 1;
5690 t = opvar_new_int(d(OV_i(a), OV_i(b)));
5691 splev_stack_push(coder->stack, t);
5692 opvar_free(a);
5693 opvar_free(b);
5694 break;
5695 }
5696 case SPO_MAP:
5697 spo_map(coder);
5698 break;
5699 case SPO_VAR_INIT:
5700 spo_var_init(coder);
5701 break;
5702 case SPO_SHUFFLE_ARRAY:
5703 spo_shuffle_array(coder);
5704 break;
5705 case SPO_SEL_ADD: /* actually, logical or */
5706 {
5707 struct opvar *sel1, *sel2, *pt;
5708
5709 if (!OV_pop_typ(sel1, SPOVAR_SEL))
5710 panic("no sel1 for add");
5711 if (!OV_pop_typ(sel2, SPOVAR_SEL))
5712 panic("no sel2 for add");
5713 pt = selection_logical_oper(sel1, sel2, '|');
5714 opvar_free(sel1);
5715 opvar_free(sel2);
5716 splev_stack_push(coder->stack, pt);
5717 break;
5718 }
5719 case SPO_SEL_COMPLEMENT: {
5720 struct opvar *sel, *pt;
5721
5722 if (!OV_pop_typ(sel, SPOVAR_SEL))
5723 panic("no sel for not");
5724 pt = selection_not(sel);
5725 opvar_free(sel);
5726 splev_stack_push(coder->stack, pt);
5727 break;
5728 }
5729 case SPO_SEL_FILTER: /* sorta like logical and */
5730 {
5731 struct opvar *filtertype;
5732
5733 if (!OV_pop_i(filtertype))
5734 panic("no sel filter type");
5735 switch (OV_i(filtertype)) {
5736 case SPOFILTER_PERCENT: {
5737 struct opvar *tmp1, *sel;
5738
5739 if (!OV_pop_i(tmp1))
5740 panic("no sel filter percent");
5741 if (!OV_pop_typ(sel, SPOVAR_SEL))
5742 panic("no sel filter");
5743 selection_filter_percent(sel, OV_i(tmp1));
5744 splev_stack_push(coder->stack, sel);
5745 opvar_free(tmp1);
5746 break;
5747 }
5748 case SPOFILTER_SELECTION: /* logical and */
5749 {
5750 struct opvar *pt, *sel1, *sel2;
5751
5752 if (!OV_pop_typ(sel1, SPOVAR_SEL))
5753 panic("no sel filter sel1");
5754 if (!OV_pop_typ(sel2, SPOVAR_SEL))
5755 panic("no sel filter sel2");
5756 pt = selection_logical_oper(sel1, sel2, '&');
5757 splev_stack_push(coder->stack, pt);
5758 opvar_free(sel1);
5759 opvar_free(sel2);
5760 break;
5761 }
5762 case SPOFILTER_MAPCHAR: {
5763 struct opvar *pt, *tmp1, *sel;
5764
5765 if (!OV_pop_typ(sel, SPOVAR_SEL))
5766 panic("no sel filter");
5767 if (!OV_pop_typ(tmp1, SPOVAR_MAPCHAR))
5768 panic("no sel filter mapchar");
5769 pt = selection_filter_mapchar(sel, tmp1);
5770 splev_stack_push(coder->stack, pt);
5771 opvar_free(tmp1);
5772 opvar_free(sel);
5773 break;
5774 }
5775 default:
5776 panic("unknown sel filter type");
5777 }
5778 opvar_free(filtertype);
5779 break;
5780 }
5781 case SPO_SEL_POINT: {
5782 struct opvar *tmp;
5783 struct opvar *pt = selection_opvar((char *) 0);
5784 schar x, y;
5785
5786 if (!OV_pop_c(tmp))
5787 panic("no ter sel coord");
5788 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp));
5789 selection_setpoint(x, y, pt, 1);
5790 splev_stack_push(coder->stack, pt);
5791 opvar_free(tmp);
5792 break;
5793 }
5794 case SPO_SEL_RECT:
5795 case SPO_SEL_FILLRECT: {
5796 struct opvar *tmp, *pt = selection_opvar((char *) 0);
5797 schar x, y, x1, y1, x2, y2;
5798
5799 if (!OV_pop_r(tmp))
5800 panic("no ter sel region");
5801 x1 = min(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp)));
5802 y1 = min(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp)));
5803 x2 = max(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp)));
5804 y2 = max(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp)));
5805 get_location(&x1, &y1, ANY_LOC, coder->croom);
5806 get_location(&x2, &y2, ANY_LOC, coder->croom);
5807 x1 = (x1 < 0) ? 0 : x1;
5808 y1 = (y1 < 0) ? 0 : y1;
5809 x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
5810 y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
5811 if (coder->opcode == SPO_SEL_RECT) {
5812 for (x = x1; x <= x2; x++) {
5813 selection_setpoint(x, y1, pt, 1);
5814 selection_setpoint(x, y2, pt, 1);
5815 }
5816 for (y = y1; y <= y2; y++) {
5817 selection_setpoint(x1, y, pt, 1);
5818 selection_setpoint(x2, y, pt, 1);
5819 }
5820 } else {
5821 for (x = x1; x <= x2; x++)
5822 for (y = y1; y <= y2; y++)
5823 selection_setpoint(x, y, pt, 1);
5824 }
5825 splev_stack_push(coder->stack, pt);
5826 opvar_free(tmp);
5827 break;
5828 }
5829 case SPO_SEL_LINE: {
5830 struct opvar *tmp = NULL, *tmp2 = NULL,
5831 *pt = selection_opvar((char *) 0);
5832 schar x1, y1, x2, y2;
5833
5834 if (!OV_pop_c(tmp))
5835 panic("no ter sel linecoord1");
5836 if (!OV_pop_c(tmp2))
5837 panic("no ter sel linecoord2");
5838 get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp));
5839 get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2));
5840 x1 = (x1 < 0) ? 0 : x1;
5841 y1 = (y1 < 0) ? 0 : y1;
5842 x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
5843 y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
5844 selection_do_line(x1, y1, x2, y2, pt);
5845 splev_stack_push(coder->stack, pt);
5846 opvar_free(tmp);
5847 opvar_free(tmp2);
5848 break;
5849 }
5850 case SPO_SEL_RNDLINE: {
5851 struct opvar *tmp = NULL, *tmp2 = NULL, *tmp3,
5852 *pt = selection_opvar((char *) 0);
5853 schar x1, y1, x2, y2;
5854
5855 if (!OV_pop_i(tmp3))
5856 panic("no ter sel randline1");
5857 if (!OV_pop_c(tmp))
5858 panic("no ter sel randline2");
5859 if (!OV_pop_c(tmp2))
5860 panic("no ter sel randline3");
5861 get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp));
5862 get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2));
5863 x1 = (x1 < 0) ? 0 : x1;
5864 y1 = (y1 < 0) ? 0 : y1;
5865 x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
5866 y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
5867 selection_do_randline(x1, y1, x2, y2, OV_i(tmp3), 12, pt);
5868 splev_stack_push(coder->stack, pt);
5869 opvar_free(tmp);
5870 opvar_free(tmp2);
5871 opvar_free(tmp3);
5872 break;
5873 }
5874 case SPO_SEL_GROW: {
5875 struct opvar *dirs, *pt;
5876
5877 if (!OV_pop_i(dirs))
5878 panic("no dirs for grow");
5879 if (!OV_pop_typ(pt, SPOVAR_SEL))
5880 panic("no selection for grow");
5881 selection_do_grow(pt, OV_i(dirs));
5882 splev_stack_push(coder->stack, pt);
5883 opvar_free(dirs);
5884 break;
5885 }
5886 case SPO_SEL_FLOOD: {
5887 struct opvar *tmp;
5888 schar x, y;
5889
5890 if (!OV_pop_c(tmp))
5891 panic("no ter sel flood coord");
5892 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp));
5893 if (isok(x, y)) {
5894 struct opvar *pt = selection_opvar((char *) 0);
5895
5896 set_selection_floodfillchk(floodfillchk_match_under);
5897 floodfillchk_match_under_typ = levl[x][y].typ;
5898 selection_floodfill(pt, x, y, FALSE);
5899 splev_stack_push(coder->stack, pt);
5900 }
5901 opvar_free(tmp);
5902 break;
5903 }
5904 case SPO_SEL_RNDCOORD: {
5905 struct opvar *pt;
5906 schar x, y;
5907
5908 if (!OV_pop_typ(pt, SPOVAR_SEL))
5909 panic("no selection for rndcoord");
5910 if (selection_rndcoord(pt, &x, &y, FALSE)) {
5911 x -= xstart;
5912 y -= ystart;
5913 }
5914 splev_stack_push(coder->stack, opvar_new_coord(x, y));
5915 opvar_free(pt);
5916 break;
5917 }
5918 case SPO_SEL_ELLIPSE: {
5919 struct opvar *filled, *xaxis, *yaxis, *pt;
5920 struct opvar *sel = selection_opvar((char *) 0);
5921 schar x, y;
5922
5923 if (!OV_pop_i(filled))
5924 panic("no filled for ellipse");
5925 if (!OV_pop_i(yaxis))
5926 panic("no yaxis for ellipse");
5927 if (!OV_pop_i(xaxis))
5928 panic("no xaxis for ellipse");
5929 if (!OV_pop_c(pt))
5930 panic("no pt for ellipse");
5931 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(pt));
5932 selection_do_ellipse(sel, x, y, OV_i(xaxis), OV_i(yaxis),
5933 OV_i(filled));
5934 splev_stack_push(coder->stack, sel);
5935 opvar_free(filled);
5936 opvar_free(yaxis);
5937 opvar_free(xaxis);
5938 opvar_free(pt);
5939 break;
5940 }
5941 case SPO_SEL_GRADIENT: {
5942 struct opvar *gtyp, *glim, *mind, *maxd, *gcoord, *coord2;
5943 struct opvar *sel;
5944 schar x, y, x2, y2;
5945
5946 if (!OV_pop_i(gtyp))
5947 panic("no gtyp for grad");
5948 if (!OV_pop_i(glim))
5949 panic("no glim for grad");
5950 if (!OV_pop_c(coord2))
5951 panic("no coord2 for grad");
5952 if (!OV_pop_c(gcoord))
5953 panic("no coord for grad");
5954 if (!OV_pop_i(maxd))
5955 panic("no maxd for grad");
5956 if (!OV_pop_i(mind))
5957 panic("no mind for grad");
5958 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(gcoord));
5959 get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(coord2));
5960
5961 sel = selection_opvar((char *) 0);
5962 selection_do_gradient(sel, x, y, x2, y2, OV_i(gtyp), OV_i(mind),
5963 OV_i(maxd), OV_i(glim));
5964 splev_stack_push(coder->stack, sel);
5965
5966 opvar_free(gtyp);
5967 opvar_free(glim);
5968 opvar_free(gcoord);
5969 opvar_free(coord2);
5970 opvar_free(maxd);
5971 opvar_free(mind);
5972 break;
5973 }
5974 default:
5975 panic("sp_level_coder: Unknown opcode %i", coder->opcode);
5976 }
5977
5978 next_opcode:
5979 coder->frame->n_opcode++;
5980 } /*while*/
5981
5982 link_doors_rooms();
5983 fill_rooms();
5984 remove_boundary_syms();
5985
5986 if (coder->check_inaccessibles)
5987 ensure_way_out();
5988 /* FIXME: Ideally, we want this call to only cover areas of the map
5989 * which were not inserted directly by the special level file (see
5990 * the insect legs on Baalzebub's level, for instance). Since that
5991 * is currently not possible, we overload the corrmaze flag for this
5992 * purpose.
5993 */
5994 if (!level.flags.corrmaze)
5995 wallification(1, 0, COLNO - 1, ROWNO - 1);
5996
5997 count_features();
5998
5999 if (coder->solidify)
6000 solidify_map();
6001
6002 /* This must be done before sokoban_detect(),
6003 * otherwise branch stairs won't be premapped. */
6004 fixup_special();
6005
6006 if (coder->premapped)
6007 sokoban_detect();
6008
6009 if (coder->frame) {
6010 struct sp_frame *tmpframe;
6011 do {
6012 tmpframe = coder->frame->next;
6013 frame_del(coder->frame);
6014 coder->frame = tmpframe;
6015 } while (coder->frame);
6016 }
6017 Free(coder);
6018
6019 return TRUE;
6020 }
6021
6022 /*
6023 * General loader
6024 */
6025 boolean
load_special(name)6026 load_special(name)
6027 const char *name;
6028 {
6029 dlb *fd;
6030 sp_lev *lvl = NULL;
6031 boolean result = FALSE;
6032 struct version_info vers_info;
6033
6034 fd = dlb_fopen(name, RDBMODE);
6035 if (!fd)
6036 return FALSE;
6037 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
6038 if (!check_version(&vers_info, name, TRUE)) {
6039 (void) dlb_fclose(fd);
6040 goto give_up;
6041 }
6042
6043 lvl = (sp_lev *) alloc(sizeof (sp_lev));
6044 result = sp_level_loader(fd, lvl);
6045 (void) dlb_fclose(fd);
6046 if (result)
6047 result = sp_level_coder(lvl);
6048 sp_level_free(lvl);
6049 Free(lvl);
6050
6051 give_up:
6052 return result;
6053 }
6054
6055 #ifdef _MSC_VER
6056 #pragma warning(pop)
6057 #endif
6058
6059 /*sp_lev.c*/
6060