OSDN Git Service

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