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