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