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