1 /* NetHack 3.6 sp_lev.c $NHDT-Date: 1553787633 2019/03/28 15:40:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.111 $ */
2 /* Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed. See license for details. */
6 * This file contains the various functions that are related to the special
9 * It contains also the special level loader.
18 #pragma warning(disable : 4244)
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 *,
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));
37 STATIC_DCL struct opvar * FDECL(opvar_new_region, (int,int, int,int));
39 STATIC_DCL struct opvar *FDECL(opvar_clone, (struct opvar *));
40 STATIC_DCL struct opvar *FDECL(opvar_var_conversion, (struct sp_coder *,
42 STATIC_DCL struct splev_var *FDECL(opvar_var_defined, (struct sp_coder *,
44 STATIC_DCL struct opvar *FDECL(splev_stack_getdat, (struct sp_coder *,
46 STATIC_DCL struct opvar *FDECL(splev_stack_getdat_any, (struct sp_coder *));
47 STATIC_DCL void FDECL(variable_list_del, (struct splev_var *));
48 STATIC_DCL void FDECL(lvlfill_maze_grid, (int, int, int, int, SCHAR_P));
49 STATIC_DCL void FDECL(lvlfill_solid, (SCHAR_P, SCHAR_P));
50 STATIC_DCL void FDECL(set_wall_property, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P,
52 STATIC_DCL void NDECL(shuffle_alignments);
53 STATIC_DCL void NDECL(count_features);
54 STATIC_DCL void NDECL(remove_boundary_syms);
55 STATIC_DCL void FDECL(set_door_orientation, (int, int));
56 STATIC_DCL void FDECL(maybe_add_door, (int, int, struct mkroom *));
57 STATIC_DCL void NDECL(link_doors_rooms);
58 STATIC_DCL void NDECL(fill_rooms);
59 STATIC_DCL int NDECL(rnddoor);
60 STATIC_DCL int NDECL(rndtrap);
61 STATIC_DCL void FDECL(get_location, (schar *, schar *, int, struct mkroom *));
62 STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
63 STATIC_DCL unpacked_coord FDECL(get_unpacked_coord, (long, int));
64 STATIC_DCL void FDECL(get_location_coord, (schar *, schar *, int,
65 struct mkroom *, long));
66 STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
67 STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *,
68 struct mkroom *, packed_coord));
69 STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
70 XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
71 STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
72 STATIC_DCL void FDECL(create_trap, (spltrap *, struct mkroom *));
73 STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
74 STATIC_DCL boolean FDECL(m_bad_boulder_spot, (int, int));
75 STATIC_DCL int FDECL(pm_to_humidity, (struct permonst *));
76 STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
77 STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
78 STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
79 STATIC_DCL void FDECL(replace_terrain, (replaceterrain *, struct mkroom *));
80 STATIC_DCL boolean FDECL(search_door, (struct mkroom *,
81 xchar *, xchar *, XCHAR_P, int));
82 STATIC_DCL void NDECL(fix_stair_rooms);
83 STATIC_DCL void FDECL(create_corridor, (corridor *));
84 STATIC_DCL struct mkroom *FDECL(build_room, (room *, struct mkroom *));
85 STATIC_DCL void FDECL(light_region, (region *));
86 STATIC_DCL void FDECL(wallify_map, (int, int, int, int));
87 STATIC_DCL void FDECL(maze1xy, (coord *, int));
88 STATIC_DCL void NDECL(fill_empty_maze);
89 STATIC_DCL boolean FDECL(sp_level_loader, (dlb *, sp_lev *));
90 STATIC_DCL boolean FDECL(sp_level_free, (sp_lev *));
91 STATIC_DCL void FDECL(splev_initlev, (lev_init *));
92 STATIC_DCL struct sp_frame *FDECL(frame_new, (long));
93 STATIC_DCL void FDECL(frame_del, (struct sp_frame *));
94 STATIC_DCL void FDECL(spo_frame_push, (struct sp_coder *));
95 STATIC_DCL void FDECL(spo_frame_pop, (struct sp_coder *));
96 STATIC_DCL long FDECL(sp_code_jmpaddr, (long, long));
97 STATIC_DCL void FDECL(spo_call, (struct sp_coder *));
98 STATIC_DCL void FDECL(spo_return, (struct sp_coder *));
99 STATIC_DCL void FDECL(spo_end_moninvent, (struct sp_coder *));
100 STATIC_DCL void FDECL(spo_pop_container, (struct sp_coder *));
101 STATIC_DCL void FDECL(spo_message, (struct sp_coder *));
102 STATIC_DCL void FDECL(spo_monster, (struct sp_coder *));
103 STATIC_DCL void FDECL(spo_object, (struct sp_coder *));
104 STATIC_DCL void FDECL(spo_level_flags, (struct sp_coder *));
105 STATIC_DCL void FDECL(spo_initlevel, (struct sp_coder *));
106 STATIC_DCL void FDECL(spo_engraving, (struct sp_coder *));
107 STATIC_DCL void FDECL(spo_mineralize, (struct sp_coder *));
108 STATIC_DCL void FDECL(spo_room, (struct sp_coder *));
109 STATIC_DCL void FDECL(spo_endroom, (struct sp_coder *));
110 STATIC_DCL void FDECL(spo_stair, (struct sp_coder *));
111 STATIC_DCL void FDECL(spo_ladder, (struct sp_coder *));
112 STATIC_DCL void FDECL(spo_grave, (struct sp_coder *));
113 STATIC_DCL void FDECL(spo_altar, (struct sp_coder *));
114 STATIC_DCL void FDECL(spo_trap, (struct sp_coder *));
115 STATIC_DCL void FDECL(spo_gold, (struct sp_coder *));
116 STATIC_DCL void FDECL(spo_corridor, (struct sp_coder *));
117 STATIC_DCL void FDECL(selection_setpoint, (int, int, struct opvar *, XCHAR_P));
118 STATIC_DCL struct opvar *FDECL(selection_not, (struct opvar *));
119 STATIC_DCL struct opvar *FDECL(selection_logical_oper, (struct opvar *,
120 struct opvar *, CHAR_P));
121 STATIC_DCL struct opvar *FDECL(selection_filter_mapchar, (struct opvar *,
123 STATIC_DCL void FDECL(selection_filter_percent, (struct opvar *, int));
124 STATIC_DCL int FDECL(selection_rndcoord, (struct opvar *, schar *, schar *,
126 STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int));
127 STATIC_DCL int FDECL(floodfillchk_match_under, (int, int));
128 STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int));
129 STATIC_DCL boolean FDECL(sel_flood_havepoint, (int, int,
130 xchar *, xchar *, int));
131 STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int,
133 STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long));
134 STATIC_DCL void FDECL(selection_do_gradient, (struct opvar *, long, long, long,
135 long, long, long, long, long));
136 STATIC_DCL void FDECL(selection_do_line, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P,
138 STATIC_DCL void FDECL(selection_do_randline, (SCHAR_P, SCHAR_P, SCHAR_P,
139 SCHAR_P, SCHAR_P, SCHAR_P,
141 STATIC_DCL void FDECL(selection_iterate, (struct opvar *, select_iter_func,
143 STATIC_DCL void FDECL(sel_set_ter, (int, int, genericptr_t));
144 STATIC_DCL void FDECL(sel_set_feature, (int, int, genericptr_t));
145 STATIC_DCL void FDECL(sel_set_door, (int, int, genericptr_t));
146 STATIC_DCL void FDECL(spo_door, (struct sp_coder *));
147 STATIC_DCL void FDECL(spo_feature, (struct sp_coder *));
148 STATIC_DCL void FDECL(spo_terrain, (struct sp_coder *));
149 STATIC_DCL void FDECL(spo_replace_terrain, (struct sp_coder *));
150 STATIC_DCL boolean FDECL(generate_way_out_method, (int, int, struct opvar *));
151 STATIC_DCL void NDECL(ensure_way_out);
152 STATIC_DCL void FDECL(spo_levregion, (struct sp_coder *));
153 STATIC_DCL void FDECL(spo_region, (struct sp_coder *));
154 STATIC_DCL void FDECL(spo_drawbridge, (struct sp_coder *));
155 STATIC_DCL void FDECL(spo_mazewalk, (struct sp_coder *));
156 STATIC_DCL void FDECL(spo_wall_property, (struct sp_coder *));
157 STATIC_DCL void FDECL(spo_room_door, (struct sp_coder *));
158 STATIC_DCL void FDECL(sel_set_wallify, (int, int, genericptr_t));
159 STATIC_DCL void FDECL(spo_wallify, (struct sp_coder *));
160 STATIC_DCL void FDECL(spo_map, (struct sp_coder *));
161 STATIC_DCL void FDECL(spo_jmp, (struct sp_coder *, sp_lev *));
162 STATIC_DCL void FDECL(spo_conditional_jump, (struct sp_coder *, sp_lev *));
163 STATIC_DCL void FDECL(spo_var_init, (struct sp_coder *));
165 STATIC_DCL long FDECL(opvar_array_length, (struct sp_coder *));
167 STATIC_DCL void FDECL(spo_shuffle_array, (struct sp_coder *));
168 STATIC_DCL boolean FDECL(sp_level_coder, (sp_lev *));
179 #define sq(x) ((x) * (x))
184 #define Fread (void) dlb_fread
185 #define Fgetc (schar) dlb_fgetc
186 #define New(type) (type *) alloc(sizeof(type))
187 #define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned) size)
188 #define Free(ptr) if (ptr) free((genericptr_t) (ptr))
190 extern struct engr *head_engr;
192 extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
194 /* positions touched by level elements explicitly defined in the des-file */
195 static char SpLev_Map[COLNO][ROWNO];
197 static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
198 static NEARDATA xchar xstart, ystart;
199 static NEARDATA char xsize, ysize;
201 char *lev_message = 0;
202 lev_region *lregions = 0;
203 int num_lregions = 0;
205 static boolean splev_init_present = FALSE;
206 static boolean icedpools = FALSE;
207 static int mines_prize_count = 0, soko_prize_count = 0; /* achievements */
209 static struct obj *container_obj[MAX_CONTAINMENT];
210 static int container_idx = 0;
211 static struct monst *invent_carrying_monster = NULL;
213 #define SPLEV_STACK_RESERVE 128
220 for (x = 0; x < COLNO; x++)
221 for (y = 0; y < ROWNO; y++)
222 if (IS_STWALL(levl[x][y].typ) && !SpLev_Map[x][y])
223 levl[x][y].wall_info |= (W_NONDIGGABLE | W_NONPASSWALL);
228 struct splevstack *st;
232 st->depth_alloc = SPLEV_STACK_RESERVE;
234 (struct opvar **) alloc(st->depth_alloc * sizeof (struct opvar *));
240 struct splevstack *st;
245 if (st->stackdata && st->depth) {
246 for (i = 0; i < st->depth; i++) {
247 switch (st->stackdata[i]->spovartyp) {
257 case SPOVAR_VARIABLE:
260 Free(st->stackdata[i]->vardata.str);
261 st->stackdata[i]->vardata.str = NULL;
264 Free(st->stackdata[i]);
265 st->stackdata[i] = NULL;
269 st->stackdata = NULL;
270 st->depth = st->depth_alloc = 0;
276 splev_stack_push(st, v)
277 struct splevstack *st;
283 panic("splev_stack_push: no stackdata allocated?");
285 if (st->depth >= st->depth_alloc) {
286 struct opvar **tmp = (struct opvar **) alloc(
287 (st->depth_alloc + SPLEV_STACK_RESERVE) * sizeof (struct opvar *));
289 (void) memcpy(tmp, st->stackdata,
290 st->depth_alloc * sizeof(struct opvar *));
293 st->depth_alloc += SPLEV_STACK_RESERVE;
296 st->stackdata[st->depth] = v;
302 struct splevstack *st;
304 struct opvar *ret = NULL;
309 panic("splev_stack_pop: no stackdata allocated?");
313 ret = st->stackdata[st->depth];
314 st->stackdata[st->depth] = NULL;
317 impossible("splev_stack_pop: empty stack?");
322 splev_stack_reverse(st)
323 struct splevstack *st;
331 panic("splev_stack_reverse: no stackdata allocated?");
332 for (i = 0; i < (st->depth / 2); i++) {
333 tmp = st->stackdata[i];
334 st->stackdata[i] = st->stackdata[st->depth - i - 1];
335 st->stackdata[st->depth - i - 1] = tmp;
340 #define OV_typ(o) (o->spovartyp)
341 #define OV_i(o) (o->vardata.l)
342 #define OV_s(o) (o->vardata.str)
344 #define OV_pop_i(x) (x = splev_stack_getdat(coder, SPOVAR_INT))
345 #define OV_pop_c(x) (x = splev_stack_getdat(coder, SPOVAR_COORD))
346 #define OV_pop_r(x) (x = splev_stack_getdat(coder, SPOVAR_REGION))
347 #define OV_pop_s(x) (x = splev_stack_getdat(coder, SPOVAR_STRING))
348 #define OV_pop(x) (x = splev_stack_getdat_any(coder))
349 #define OV_pop_typ(x, typ) (x = splev_stack_getdat(coder, typ))
355 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
357 tmpov->spovartyp = SPOVAR_STRING;
360 tmpov->vardata.str = (char *) alloc(len + 1);
361 (void) memcpy((genericptr_t) tmpov->vardata.str, (genericptr_t) s,
363 tmpov->vardata.str[len] = '\0';
365 tmpov->vardata.str = NULL;
373 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
375 tmpov->spovartyp = SPOVAR_INT;
376 tmpov->vardata.l = i;
381 opvar_new_coord(x, y)
384 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
386 tmpov->spovartyp = SPOVAR_COORD;
387 tmpov->vardata.l = SP_COORD_PACK(x, y);
393 opvar_new_region(x1,y1,x2,y2)
396 struct opvar *tmpov = (struct opvar *) alloc(sizeof (struct opvar));
398 tmpov->spovartyp = SPOVAR_REGION;
399 tmpov->vardata.l = SP_REGION_PACK(x1,y1,x2,y2);
410 switch (ov->spovartyp) {
418 case SPOVAR_VARIABLE:
421 Free(ov->vardata.str);
424 impossible("Unknown opvar value type (%i)!", ov->spovartyp);
430 * Name of current function for use in messages:
431 * __func__ -- C99 standard;
432 * __FUNCTION__ -- gcc extension, starting before C99 and continuing after;
433 * picked up by other compilers (or vice versa?);
434 * __FUNC__ -- supported by Borland;
435 * nhFunc -- slightly intrusive but fully portable nethack construct
436 * for any version of any compiler.
438 #define opvar_free(ov) \
444 impossible("opvar_free(), %s", nhFunc); \
454 panic("no opvar to clone");
455 tmpov = (struct opvar *) alloc(sizeof(struct opvar));
456 tmpov->spovartyp = ov->spovartyp;
457 switch (ov->spovartyp) {
464 tmpov->vardata.l = ov->vardata.l;
466 case SPOVAR_VARIABLE:
469 tmpov->vardata.str = dupstr(ov->vardata.str);
472 impossible("Unknown push value type (%i)!", ov->spovartyp);
478 opvar_var_conversion(coder, ov)
479 struct sp_coder *coder;
482 static const char nhFunc[] = "opvar_var_conversion";
483 struct splev_var *tmp;
485 struct opvar *array_idx = NULL;
489 if (ov->spovartyp != SPOVAR_VARIABLE)
491 tmp = coder->frame->variables;
493 if (!strcmp(tmp->name, OV_s(ov))) {
494 if ((tmp->svtyp & SPOVAR_ARRAY)) {
495 array_idx = opvar_var_conversion(coder,
496 splev_stack_pop(coder->stack));
497 if (!array_idx || OV_typ(array_idx) != SPOVAR_INT)
498 panic("array idx not an int");
499 if (tmp->array_len < 1)
500 panic("array len < 1");
501 OV_i(array_idx) = (OV_i(array_idx) % tmp->array_len);
502 tmpov = opvar_clone(tmp->data.arrayvalues[OV_i(array_idx)]);
503 opvar_free(array_idx);
506 tmpov = opvar_clone(tmp->data.value);
516 opvar_var_defined(coder, name)
517 struct sp_coder *coder;
520 struct splev_var *tmp;
524 tmp = coder->frame->variables;
526 if (!strcmp(tmp->name, name))
534 splev_stack_getdat(coder, typ)
535 struct sp_coder *coder;
538 static const char nhFunc[] = "splev_stack_getdat";
539 if (coder && coder->stack) {
540 struct opvar *tmp = splev_stack_pop(coder->stack);
541 struct opvar *ret = NULL;
544 panic("no value type %i in stack.", typ);
545 if (tmp->spovartyp == SPOVAR_VARIABLE) {
546 ret = opvar_var_conversion(coder, tmp);
550 if (tmp->spovartyp == typ)
552 else opvar_free(tmp);
558 splev_stack_getdat_any(coder)
559 struct sp_coder *coder;
561 static const char nhFunc[] = "splev_stack_getdat_any";
562 if (coder && coder->stack) {
563 struct opvar *tmp = splev_stack_pop(coder->stack);
564 if (tmp && tmp->spovartyp == SPOVAR_VARIABLE) {
565 struct opvar *ret = opvar_var_conversion(coder, tmp);
575 variable_list_del(varlist)
576 struct splev_var *varlist;
578 static const char nhFunc[] = "variable_list_del";
579 struct splev_var *tmp = varlist;
585 if ((tmp->svtyp & SPOVAR_ARRAY)) {
586 long idx = tmp->array_len;
589 opvar_free(tmp->data.arrayvalues[idx]);
591 Free(tmp->data.arrayvalues);
593 opvar_free(tmp->data.value);
602 lvlfill_maze_grid(x1, y1, x2, y2, filling)
608 for (x = x1; x <= x2; x++)
609 for (y = y1; y <= y2; y++) {
610 if (level.flags.corrmaze)
611 levl[x][y].typ = STONE;
613 levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE
619 lvlfill_solid(filling, lit)
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
635 set_wall_property(x1, y1, x2, y2, prop)
636 xchar x1, y1, x2, y2;
643 x2 = min(x2, COLNO - 1);
645 y2 = min(y2, ROWNO - 1);
646 for (y = y1; y <= y2; y++)
647 for (x = x1; x <= x2; x++) {
649 if (IS_STWALL(lev->typ) || IS_TREE(lev->typ)
650 /* 3.6.2: made iron bars eligible to be flagged nondiggable
651 (checked by chewing(hack.c) and zap_over_floor(zap.c)) */
652 || lev->typ == IRONBARS)
653 lev->wall_info |= prop;
663 /* shuffle 3 alignments */
666 ralign[2] = ralign[i];
670 ralign[1] = ralign[0];
676 * Count the different features (sinks, fountains) in the level.
683 level.flags.nfountains = level.flags.nsinks = 0;
684 for (y = 0; y < ROWNO; y++)
685 for (x = 0; x < COLNO; x++) {
686 int typ = levl[x][y].typ;
688 level.flags.nfountains++;
689 else if (typ == SINK)
690 level.flags.nsinks++;
695 remove_boundary_syms()
698 * If any CROSSWALLs are found, must change to ROOM after REGION's
699 * are laid out. CROSSWALLS are used to specify "invisible"
700 * boundaries where DOOR syms look bad or aren't desirable.
703 boolean has_bounds = FALSE;
705 for (x = 0; x < COLNO - 1; x++)
706 for (y = 0; y < ROWNO - 1; y++)
707 if (levl[x][y].typ == CROSSWALL) {
712 for (x = 0; x < x_maze_max; x++)
713 for (y = 0; y < y_maze_max; y++)
714 if ((levl[x][y].typ == CROSSWALL) && SpLev_Map[x][y])
715 levl[x][y].typ = ROOM;
719 /* used by sel_set_door() and link_doors_rooms() */
721 set_door_orientation(x, y)
724 boolean wleft, wright, wup, wdown;
726 /* If there's a wall or door on either the left side or right
727 * side (or both) of this secret door, make it be horizontal.
729 * It is feasible to put SDOOR in a corner, tee, or crosswall
730 * position, although once the door is found and opened it won't
731 * make a lot sense (diagonal access required). Still, we try to
732 * handle that as best as possible. For top or bottom tee, using
733 * horizontal is the best we can do. For corner or crosswall,
734 * either horizontal or vertical are just as good as each other;
735 * we produce horizontal for corners and vertical for crosswalls.
736 * For left or right tee, using vertical is best.
738 * A secret door with no adjacent walls is also feasible and makes
739 * even less sense. It will be displayed as a vertical wall while
740 * hidden and become a vertical door when found. Before resorting
741 * to that, we check for solid rock which hasn't been wallified
742 * yet (cf lower leftside of leader's room in Cav quest).
744 wleft = (isok(x - 1, y) && (IS_WALL(levl[x - 1][y].typ)
745 || IS_DOOR(levl[x - 1][y].typ)
746 || levl[x - 1][y].typ == SDOOR));
747 wright = (isok(x + 1, y) && (IS_WALL(levl[x + 1][y].typ)
748 || IS_DOOR(levl[x + 1][y].typ)
749 || levl[x + 1][y].typ == SDOOR));
750 wup = (isok(x, y - 1) && (IS_WALL(levl[x][y - 1].typ)
751 || IS_DOOR(levl[x][y - 1].typ)
752 || levl[x][y - 1].typ == SDOOR));
753 wdown = (isok(x, y + 1) && (IS_WALL(levl[x][y + 1].typ)
754 || IS_DOOR(levl[x][y + 1].typ)
755 || levl[x][y + 1].typ == SDOOR));
756 if (!wleft && !wright && !wup && !wdown) {
757 /* out of bounds is treated as implicit wall; should be academic
758 because we don't expect to have doors so near the level's edge */
759 wleft = (!isok(x - 1, y) || IS_DOORJOIN(levl[x - 1][y].typ));
760 wright = (!isok(x + 1, y) || IS_DOORJOIN(levl[x + 1][y].typ));
761 wup = (!isok(x, y - 1) || IS_DOORJOIN(levl[x][y - 1].typ));
762 wdown = (!isok(x, y + 1) || IS_DOORJOIN(levl[x][y + 1].typ));
764 levl[x][y].horizontal = ((wleft || wright) && !(wup && wdown)) ? 1 : 0;
768 maybe_add_door(x, y, droom)
770 struct mkroom *droom;
772 if (droom->hx >= 0 && doorindex < DOORMAX && inside_room(droom, x, y))
773 add_door(x, y, droom);
782 for (y = 0; y < ROWNO; y++)
783 for (x = 0; x < COLNO; x++)
784 if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) {
785 /* in case this door was a '+' or 'S' from the
786 MAP...ENDMAP section without an explicit DOOR
787 directive, set/clear levl[][].horizontal for it */
788 set_door_orientation(x, y);
790 for (tmpi = 0; tmpi < nroom; tmpi++) {
791 maybe_add_door(x, y, &rooms[tmpi]);
792 for (m = 0; m < rooms[tmpi].nsubrooms; m++) {
793 maybe_add_door(x, y, rooms[tmpi].sbrooms[m]);
804 for (tmpi = 0; tmpi < nroom; tmpi++) {
805 if (rooms[tmpi].needfill)
806 fill_room(&rooms[tmpi], (rooms[tmpi].needfill == 2));
807 for (m = 0; m < rooms[tmpi].nsubrooms; m++)
808 if (rooms[tmpi].sbrooms[m]->needfill)
809 fill_room(rooms[tmpi].sbrooms[m], FALSE);
814 * Choose randomly the state (nodoor, open, closed or locked) for a door
826 * Select a random trap
834 rtrap = rnd(TRAPNUM - 1);
836 case HOLE: /* no random holes on special levels */
837 case VIBRATING_SQUARE:
842 if (!Can_dig_down(&u.uz))
847 if (level.flags.noteleport)
850 case ROLLING_BOULDER_TRAP:
852 if (In_endgame(&u.uz))
856 } while (rtrap == NO_TRAP);
861 * Coordinates in special level files are handled specially:
863 * if x or y is < 0, we generate a random coordinate.
864 * The "humidity" flag is used to insure that engravings aren't
865 * created underwater, or eels on dry land.
868 get_location(x, y, humidity, croom)
871 struct mkroom *croom;
879 sx = croom->hx - mx + 1;
880 sy = croom->hy - my + 1;
888 if (*x >= 0) { /* normal locations */
891 } else { /* random location */
893 if (croom) { /* handle irregular areas */
895 somexy(croom, &tmpc);
899 *x = mx + rn2((int) sx);
900 *y = my + rn2((int) sy);
902 if (is_ok_location(*x, *y, humidity))
904 } while (++cpt < 100);
909 for (xx = 0; xx < sx; xx++)
910 for (yy = 0; yy < sy; yy++) {
913 if (is_ok_location(*x, *y, humidity))
916 if (!(humidity & NO_LOC_WARN)) {
917 impossible("get_location: can't find a place!");
926 if (!(humidity & ANY_LOC) && !isok(*x, *y)) {
927 if (!(humidity & NO_LOC_WARN)) {
928 /*warning("get_location: (%d,%d) out of bounds", *x, *y);*/
938 is_ok_location(x, y, humidity)
940 register int humidity;
944 if (Is_waterlevel(&u.uz))
945 return TRUE; /* accept any spot */
947 /* TODO: Should perhaps check if wall is diggable/passwall? */
948 if (humidity & ANY_LOC)
951 if ((humidity & SOLID) && IS_ROCK(levl[x][y].typ))
954 if (humidity & DRY) {
955 typ = levl[x][y].typ;
956 if (typ == ROOM || typ == AIR || typ == CLOUD || typ == ICE
960 if ((humidity & SPACELOC) && SPACE_POS(levl[x][y].typ))
962 if ((humidity & WET) && is_pool(x, y))
964 if ((humidity & HOT) && is_lava(x, y))
970 get_unpacked_coord(loc, defhumidity)
974 static unpacked_coord c;
976 if (loc & SP_COORD_IS_RANDOM) {
979 c.getloc_flags = (loc & ~SP_COORD_IS_RANDOM);
981 c.getloc_flags = defhumidity;
984 c.getloc_flags = defhumidity;
985 c.x = SP_COORD_X(loc);
986 c.y = SP_COORD_Y(loc);
992 get_location_coord(x, y, humidity, croom, crd)
995 struct mkroom *croom;
1000 c = get_unpacked_coord(crd, humidity);
1003 get_location(x, y, c.getloc_flags | (c.is_random ? NO_LOC_WARN : 0),
1005 if (*x == -1 && *y == -1 && c.is_random)
1006 get_location(x, y, humidity, croom);
1010 * Get a relative position inside a room.
1011 * negative values for x or y means RANDOM!
1015 get_room_loc(x, y, croom)
1017 struct mkroom *croom;
1021 if (*x < 0 && *y < 0) {
1022 if (somexy(croom, &c)) {
1026 panic("get_room_loc : can't find a place!");
1029 *x = rn2(croom->hx - croom->lx + 1);
1031 *y = rn2(croom->hy - croom->ly + 1);
1038 * Get a relative position inside a room.
1039 * negative values for x or y means RANDOM!
1042 get_free_room_loc(x, y, croom, pos)
1044 struct mkroom *croom;
1048 register int trycnt = 0;
1050 get_location_coord(&try_x, &try_y, DRY, croom, pos);
1051 if (levl[try_x][try_y].typ != ROOM) {
1053 try_x = *x, try_y = *y;
1054 get_room_loc(&try_x, &try_y, croom);
1055 } while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100);
1058 panic("get_free_room_loc: can't find a place!");
1060 *x = try_x, *y = try_y;
1064 check_room(lowx, ddx, lowy, ddy, vault)
1065 xchar *lowx, *ddx, *lowy, *ddy;
1068 register int x, y, hix = *lowx + *ddx, hiy = *lowy + *ddy;
1069 register struct rm *lev;
1070 int xlim, ylim, ymax;
1072 xlim = XLIM + (vault ? 1 : 0);
1073 ylim = YLIM + (vault ? 1 : 0);
1079 if (hix > COLNO - 3)
1081 if (hiy > ROWNO - 3)
1084 if (hix <= *lowx || hiy <= *lowy)
1087 /* check area around room (and make room smaller if necessary) */
1088 for (x = *lowx - xlim; x <= hix + xlim; x++) {
1089 if (x <= 0 || x >= COLNO)
1098 for (; y <= ymax; y++) {
1101 debugpline2("strange area [%d,%d] in check_room.", x, y);
1106 *lowx = x + xlim + 1;
1110 *lowy = y + ylim + 1;
1123 * Create a new room.
1124 * This is still very incomplete...
1127 create_room(x, y, w, h, xal, yal, rtype, rlit)
1133 xchar xabs = 0, yabs = 0;
1134 int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp;
1137 boolean vault = FALSE;
1138 int xlim = XLIM, ylim = YLIM;
1140 if (rtype == -1) /* Is the type random ? */
1143 if (rtype == VAULT) {
1149 /* on low levels the room is lit (usually) */
1150 /* some other rooms may require lighting */
1152 /* is light state random ? */
1154 rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
1157 * Here we will try to create a room. If some parameters are
1158 * random we are willing to make several try before we give
1162 xchar xborder, yborder;
1170 /* First case : a totally random room */
1172 if ((xtmp < 0 && ytmp < 0 && wtmp < 0 && xaltmp < 0 && yaltmp < 0)
1174 xchar hx, hy, lx, ly, dx, dy;
1175 r1 = rnd_rect(); /* Get a random rectangle */
1177 if (!r1) { /* No more free rectangles ! */
1178 debugpline0("No more rects...");
1188 dx = 2 + rn2((hx - lx > 28) ? 12 : 8);
1193 xborder = (lx > 0 && hx < COLNO - 1) ? 2 * xlim : xlim + 1;
1194 yborder = (ly > 0 && hy < ROWNO - 1) ? 2 * ylim : ylim + 1;
1195 if (hx - lx < dx + 3 + xborder || hy - ly < dy + 3 + yborder) {
1199 xabs = lx + (lx > 0 ? xlim : 3)
1200 + rn2(hx - (lx > 0 ? lx : 3) - dx - xborder + 1);
1201 yabs = ly + (ly > 0 ? ylim : 2)
1202 + rn2(hy - (ly > 0 ? ly : 2) - dy - yborder + 1);
1203 if (ly == 0 && hy >= (ROWNO - 1) && (!nroom || !rn2(nroom))
1204 && (yabs + dy > ROWNO / 2)) {
1206 if (nroom < 4 && dy > 1)
1209 if (!check_room(&xabs, &dx, &yabs, &dy, vault)) {
1217 r2.hx = xabs + wtmp;
1218 r2.hy = yabs + htmp;
1219 } else { /* Only some parameters are random */
1221 if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */
1226 if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */
1230 if (xaltmp == -1) /* Horizontal alignment is RANDOM */
1232 if (yaltmp == -1) /* Vertical alignment is RANDOM */
1235 /* Try to generate real (absolute) coordinates here! */
1237 xabs = (((xtmp - 1) * COLNO) / 5) + 1;
1238 yabs = (((ytmp - 1) * ROWNO) / 5) + 1;
1243 xabs += (COLNO / 5) - wtmp;
1246 xabs += ((COLNO / 5) - wtmp) / 2;
1253 yabs += (ROWNO / 5) - htmp;
1256 yabs += ((ROWNO / 5) - htmp) / 2;
1260 if (xabs + wtmp - 1 > COLNO - 2)
1261 xabs = COLNO - wtmp - 3;
1264 if (yabs + htmp - 1 > ROWNO - 2)
1265 yabs = ROWNO - htmp - 3;
1269 /* Try to find a rectangle that fit our room ! */
1273 r2.hx = xabs + wtmp + rndpos;
1274 r2.hy = yabs + htmp + rndpos;
1277 } while (++trycnt <= 100 && !r1);
1278 if (!r1) { /* creation of room failed ? */
1281 split_rects(r1, &r2);
1284 smeq[nroom] = nroom;
1285 add_room(xabs, yabs, xabs + wtmp - 1, yabs + htmp - 1, rlit, rtype,
1288 rooms[nroom].lx = xabs;
1289 rooms[nroom].ly = yabs;
1295 * Create a subroom in room proom at pos x,y with width w & height h.
1296 * x & y are relative to the parent room.
1299 create_subroom(proom, x, y, w, h, rtype, rlit)
1300 struct mkroom *proom;
1305 xchar width, height;
1307 width = proom->hx - proom->lx + 1;
1308 height = proom->hy - proom->ly + 1;
1310 /* There is a minimum size for the parent room */
1311 if (width < 4 || height < 4)
1314 /* Check for random position, size, etc... */
1319 h = rnd(height - 3);
1321 x = rnd(width - w - 1) - 1;
1323 y = rnd(height - h - 1) - 1;
1328 if ((x + w + 1) == width)
1330 if ((y + h + 1) == height)
1335 rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
1336 add_subroom(proom, proom->lx + x, proom->ly + y, proom->lx + x + w - 1,
1337 proom->ly + y + h - 1, rlit, rtype, FALSE);
1342 * Create a new door in a room.
1343 * It's placed on a wall (north, south, east or west).
1346 create_door(dd, broom)
1348 struct mkroom *broom;
1351 int trycnt = 0, wtry = 0;
1353 if (dd->secret == -1)
1354 dd->secret = rn2(2);
1356 if (dd->mask == -1) {
1357 /* is it a locked door, closed, or a doorway? */
1361 dd->mask = D_ISOPEN;
1363 dd->mask = D_LOCKED;
1365 dd->mask = D_CLOSED;
1366 if (dd->mask != D_ISOPEN && !rn2(25))
1367 dd->mask |= D_TRAPPED;
1369 dd->mask = D_NODOOR;
1372 dd->mask = D_LOCKED;
1374 dd->mask = D_CLOSED;
1377 dd->mask |= D_TRAPPED;
1382 register int dwall, dpos;
1385 if (dwall == -1) /* The wall is RANDOM */
1386 dwall = 1 << rn2(4);
1390 /* Convert wall and pos into an absolute coordinate! */
1394 if (!(dwall & W_NORTH))
1398 + ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos);
1399 if (IS_ROCK(levl[x][y - 1].typ))
1403 if (!(dwall & W_SOUTH))
1407 + ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos);
1408 if (IS_ROCK(levl[x][y + 1].typ))
1412 if (!(dwall & W_WEST))
1416 + ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos);
1417 if (IS_ROCK(levl[x - 1][y].typ))
1421 if (!(dwall & W_EAST))
1425 + ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos);
1426 if (IS_ROCK(levl[x + 1][y].typ))
1431 panic("create_door: No wall for door!");
1439 } while (++trycnt <= 100);
1441 impossible("create_door: Can't find a proper place!");
1444 levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
1445 levl[x][y].doormask = dd->mask;
1449 * Create a secret door in croom on any one of the specified walls.
1452 create_secret_door(croom, walls)
1453 struct mkroom *croom;
1454 xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
1456 xchar sx, sy; /* location of the secret door */
1459 for (count = 0; count < 100; count++) {
1460 sx = rn1(croom->hx - croom->lx + 1, croom->lx);
1461 sy = rn1(croom->hy - croom->ly + 1, croom->ly);
1465 if (!(walls & W_NORTH))
1469 case 1: /* bottom */
1470 if (!(walls & W_SOUTH))
1475 if (!(walls & W_EAST))
1480 if (!(walls & W_WEST))
1486 if (okdoor(sx, sy)) {
1487 levl[sx][sy].typ = SDOOR;
1488 levl[sx][sy].doormask = D_CLOSED;
1493 impossible("couldn't create secret door on any walls 0x%x", walls);
1497 * Create a trap in a room.
1500 create_trap(t, croom)
1502 struct mkroom *croom;
1504 schar x = -1, y = -1;
1508 get_free_room_loc(&x, &y, croom, t->coord);
1512 get_location_coord(&x, &y, DRY, croom, t->coord);
1513 } while ((levl[x][y].typ == STAIRS || levl[x][y].typ == LADDER)
1514 && ++trycnt <= 100);
1522 mktrap(t->type, 1, (struct mkroom *) 0, &tm);
1526 * Create a monster in a room.
1529 noncoalignment(alignment)
1536 return (k ? -1 : 1);
1537 return (k ? -alignment : 0);
1540 /* attempt to screen out locations where a mimic-as-boulder shouldn't occur */
1542 m_bad_boulder_spot(x, y)
1547 /* avoid trap locations */
1550 /* try to avoid locations which already have a boulder (this won't
1551 actually work; we get called before objects have been placed...) */
1552 if (sobj_at(BOULDER, x, y))
1554 /* avoid closed doors */
1556 if (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED | D_LOCKED)) != 0)
1564 struct permonst *pm;
1569 if (pm->mlet == S_EEL || amphibious(pm) || is_swimmer(pm))
1571 if (is_flyer(pm) || is_floater(pm))
1573 if (passes_walls(pm) || noncorporeal(pm))
1581 create_monster(m, croom)
1583 struct mkroom *croom;
1590 struct permonst *pm;
1594 class = (char) def_char_to_monclass((char) m->class);
1598 if (class == MAXMCLASSES)
1599 panic("create_monster: unknown monster class '%c'", m->class);
1601 amask = (m->align == AM_SPLEV_CO)
1602 ? Align2amask(u.ualignbase[A_ORIGINAL])
1603 : (m->align == AM_SPLEV_NONCO)
1604 ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL]))
1605 : (m->align <= -(MAX_REGISTERS + 1))
1607 : (m->align < 0 ? ralign[-m->align - 1] : m->align);
1610 pm = (struct permonst *) 0;
1611 else if (m->id != NON_PM) {
1613 g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags;
1614 if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT))
1616 else if (g_mvflags & G_GONE) /* genocided or extinct */
1617 pm = (struct permonst *) 0; /* make random monster */
1619 pm = mkclass(class, G_NOGEN);
1620 /* if we can't get a specific monster type (pm == 0) then the
1621 class has been genocided, so settle for a random monster */
1623 if (In_mines(&u.uz) && pm && your_race(pm)
1624 && (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3))
1625 pm = (struct permonst *) 0;
1628 int loc = pm_to_humidity(pm);
1629 /* If water-liking monster, first try is without DRY */
1630 get_location_coord(&x, &y, loc | NO_LOC_WARN, croom, m->coord);
1631 if (x == -1 && y == -1) {
1633 get_location_coord(&x, &y, loc, croom, m->coord);
1636 get_location_coord(&x, &y, DRY, croom, m->coord);
1639 /* try to find a close place if someone else is already there */
1640 if (MON_AT(x, y) && enexto(&cc, x, y, pm))
1643 if (m->align != -(MAX_REGISTERS + 2))
1644 mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful);
1645 else if (PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD)
1646 mtmp = mk_mplayer(pm, x, y, FALSE);
1648 mtmp = makemon(pm, x, y, NO_MM_FLAGS);
1651 x = mtmp->mx, y = mtmp->my; /* sanity precaution */
1653 /* handle specific attributes for some special monsters */
1655 mtmp = christen_monst(mtmp, m->name.str);
1658 * This doesn't complain if an attempt is made to give a
1659 * non-mimic/non-shapechanger an appearance or to give a
1660 * shapechanger a non-monster shape, it just refuses to comply.
1662 if (m->appear_as.str
1663 && ((mtmp->data->mlet == S_MIMIC)
1664 /* shapechanger (chameleons, et al, and vampires) */
1665 || (mtmp->cham >= LOW_PM && m->appear == M_AP_MONSTER))
1666 && !Protection_from_shape_changers) {
1669 switch (m->appear) {
1672 "create_monster: mon has an appearance, \"%s\", but no type",
1676 case M_AP_FURNITURE:
1677 for (i = 0; i < MAXPCHARS; i++)
1678 if (!strcmp(defsyms[i].explanation, m->appear_as.str))
1680 if (i == MAXPCHARS) {
1681 impossible("create_monster: can't find feature \"%s\"",
1684 mtmp->m_ap_type = M_AP_FURNITURE;
1685 mtmp->mappearance = i;
1690 for (i = 0; i < NUM_OBJECTS; i++)
1691 if (OBJ_NAME(objects[i])
1692 && !strcmp(OBJ_NAME(objects[i]), m->appear_as.str))
1694 if (i == NUM_OBJECTS) {
1695 impossible("create_monster: can't find object \"%s\"",
1698 mtmp->m_ap_type = M_AP_OBJECT;
1699 mtmp->mappearance = i;
1700 /* try to avoid placing mimic boulder on a trap */
1701 if (i == BOULDER && m->x < 0
1702 && m_bad_boulder_spot(x, y)) {
1703 int retrylimit = 10;
1705 remove_monster(x, y);
1709 get_location(&x, &y, DRY, croom);
1710 if (MON_AT(x, y) && enexto(&cc, x, y, pm))
1712 } while (m_bad_boulder_spot(x, y)
1713 && --retrylimit > 0);
1714 place_monster(mtmp, x, y);
1715 /* if we didn't find a good spot
1716 then mimic something else */
1718 set_mimic_sym(mtmp);
1723 case M_AP_MONSTER: {
1726 if (!strcmpi(m->appear_as.str, "random"))
1727 mndx = select_newcham_form(mtmp);
1729 mndx = name_to_mon(m->appear_as.str);
1731 if (mndx == NON_PM || (is_vampshifter(mtmp)
1732 && !validvamp(mtmp, &mndx, S_HUMAN))) {
1733 impossible("create_monster: invalid %s (\"%s\")",
1734 (mtmp->data->mlet == S_MIMIC)
1735 ? "mimic appearance"
1736 : (mtmp->data == &mons[PM_WIZARD_OF_YENDOR])
1737 ? "Wizard appearance"
1738 : is_vampshifter(mtmp)
1740 : "chameleon shape",
1742 } else if (&mons[mndx] == mtmp->data) {
1743 /* explicitly forcing a mimic to appear as itself */
1744 mtmp->m_ap_type = M_AP_NOTHING;
1745 mtmp->mappearance = 0;
1746 } else if (mtmp->data->mlet == S_MIMIC
1747 || mtmp->data == &mons[PM_WIZARD_OF_YENDOR]) {
1748 /* this is ordinarily only used for Wizard clones
1749 and hasn't been exhaustively tested for mimics */
1750 mtmp->m_ap_type = M_AP_MONSTER;
1751 mtmp->mappearance = mndx;
1752 } else { /* chameleon or vampire */
1753 struct permonst *mdat = &mons[mndx];
1754 struct permonst *olddata = mtmp->data;
1756 mgender_from_permonst(mtmp, mdat);
1757 set_mon_data(mtmp, mdat);
1758 if (emits_light(olddata) != emits_light(mtmp->data)) {
1759 /* used to give light, now doesn't, or vice versa,
1760 or light's range has changed */
1761 if (emits_light(olddata))
1762 del_light_source(LS_MONSTER, (genericptr_t) mtmp);
1763 if (emits_light(mtmp->data))
1764 new_light_source(mtmp->mx, mtmp->my,
1765 emits_light(mtmp->data),
1766 LS_MONSTER, (genericptr_t) mtmp);
1768 if (!mtmp->perminvis || pm_invisible(olddata))
1769 mtmp->perminvis = pm_invisible(mdat);
1775 "create_monster: unimplemented mon appear type [%d,\"%s\"]",
1776 m->appear, m->appear_as.str);
1779 if (does_block(x, y, &levl[x][y]))
1783 if (m->peaceful >= 0) {
1784 mtmp->mpeaceful = m->peaceful;
1785 /* changed mpeaceful again; have to reset malign */
1788 if (m->asleep >= 0) {
1790 /* optimizer bug strikes again */
1792 mtmp->msleeping = 1;
1794 mtmp->msleeping = 0;
1796 mtmp->msleeping = m->asleep;
1800 mtmp->mtrapseen = m->seentraps;
1814 mtmp->minvis = mtmp->perminvis = 1;
1818 mtmp->mblinded = (m->blinded % 127);
1822 mtmp->mfrozen = (m->paralyzed % 127);
1826 mtmp->mfleetim = (m->fleeing % 127);
1829 if (m->has_invent) {
1830 discard_minvent(mtmp);
1831 invent_carrying_monster = mtmp;
1837 * Create an object in a room.
1840 create_object(o, croom)
1842 struct mkroom *croom;
1847 boolean named; /* has a name been supplied in level description? */
1849 named = o->name.str ? TRUE : FALSE;
1851 get_location_coord(&x, &y, DRY, croom, o->coord);
1859 otmp = mkobj_at(RANDOM_CLASS, x, y, !named);
1860 else if (o->id != -1)
1861 otmp = mksobj_at(o->id, x, y, TRUE, !named);
1864 * The special levels are compiled with the default "text" object
1865 * class characters. We must convert them to the internal format.
1867 char oclass = (char) def_char_to_objclass(c);
1869 if (oclass == MAXOCLASSES)
1870 panic("create_object: unexpected object class '%c'", c);
1872 /* KMH -- Create piles of gold properly */
1873 if (oclass == COIN_CLASS)
1874 otmp = mkgold(0L, x, y);
1876 otmp = mkobj_at(oclass, x, y, !named);
1879 if (o->spe != -127) /* That means NOT RANDOM! */
1880 otmp->spe = (schar) o->spe;
1882 switch (o->curse_state) {
1885 break; /* BLESSED */
1889 break; /* uncursed */
1894 break; /* Otherwise it's random and we're happy
1895 * with what mkobj gave us! */
1898 /* corpsenm is "empty" if -1, random if -2, otherwise specific */
1899 if (o->corpsenm != NON_PM) {
1900 if (o->corpsenm == NON_PM - 1)
1901 set_corpsenm(otmp, rndmonnum());
1903 set_corpsenm(otmp, o->corpsenm);
1905 /* set_corpsenm() took care of egg hatch and corpse timers */
1908 otmp = oname(otmp, o->name.str);
1911 if (o->eroded < 0) {
1912 otmp->oerodeproof = 1;
1914 otmp->oeroded = (o->eroded % 4);
1915 otmp->oeroded2 = ((o->eroded >> 2) % 4);
1919 otmp->recharged = (o->recharged % 8);
1922 } else if (o->broken) {
1924 otmp->olocked = 0; /* obj generation may set */
1926 if (o->trapped == 0 || o->trapped == 1)
1927 otmp->otrapped = o->trapped;
1930 #ifdef INVISIBLE_OBJECTS
1935 if (o->quan > 0 && objects[otmp->otyp].oc_merge) {
1936 otmp->quan = o->quan;
1937 otmp->owt = weight(otmp);
1941 if (o->containment & SP_OBJ_CONTENT) {
1942 if (!container_idx) {
1943 if (!invent_carrying_monster) {
1944 /*impossible("create_object: no container");*/
1945 /* don't complain, the monster may be gone legally
1946 (eg. unique demon already generated)
1947 TODO: In the case of unique demon lords, they should
1948 get their inventories even when they get generated
1949 outside the des-file. Maybe another data file that
1950 determines what inventories monsters get by default?
1954 struct obj *objcheck = otmp;
1957 for (ci = 0; ci < container_idx; ci++)
1958 if (container_obj[ci] == objcheck)
1960 remove_object(otmp);
1961 if (mpickobj(invent_carrying_monster, otmp)) {
1964 "container given to monster was merged or deallocated.");
1965 for (ci = inuse; ci < container_idx - 1; ci++)
1966 container_obj[ci] = container_obj[ci + 1];
1967 container_obj[container_idx] = NULL;
1970 /* we lost track of it. */
1975 struct obj *cobj = container_obj[container_idx - 1];
1977 remove_object(otmp);
1979 (void) add_to_container(cobj, otmp);
1980 cobj->owt = weight(cobj);
1982 obj_extract_self(otmp);
1989 if (o->containment & SP_OBJ_CONTAINER) {
1990 delete_contents(otmp);
1991 if (container_idx < MAX_CONTAINMENT) {
1992 container_obj[container_idx] = otmp;
1995 impossible("create_object: too deeply nested containers.");
1998 /* Medusa level special case: statues are petrified monsters, so they
1999 * are not stone-resistant and have monster inventory. They also lack
2000 * other contents, but that can be specified as an empty container.
2002 if (o->id == STATUE && Is_medusa_level(&u.uz) && o->corpsenm == NON_PM) {
2003 struct monst *was = NULL;
2006 int i = 0; /* prevent endless loop in case makemon always fails */
2008 /* Named random statues are of player types, and aren't stone-
2009 * resistant (if they were, we'd have to reset the name as well as
2010 * setting corpsenm).
2012 for (wastyp = otmp->corpsenm; i < 1000; i++, wastyp = rndmonnum()) {
2013 /* makemon without rndmonst() might create a group */
2014 was = makemon(&mons[wastyp], 0, 0, MM_NOCOUNTBIRTH);
2016 if (!resists_ston(was)) {
2017 (void) propagate(wastyp, TRUE, FALSE);
2025 set_corpsenm(otmp, wastyp);
2026 while (was->minvent) {
2029 obj_extract_self(obj);
2030 (void) add_to_container(otmp, obj);
2032 otmp->owt = weight(otmp);
2038 static const char prize_warning[] = "multiple prizes on %s level";
2040 /* if this is a specific item of the right type and it is being
2041 created on the right level, flag it as the designated item
2042 used to detect a special achievement (to whit, reaching and
2043 exploring the target level, although the exploration part
2044 might be short-circuited if a monster brings object to hero) */
2045 if (Is_mineend_level(&u.uz)) {
2046 if (otmp->otyp == iflags.mines_prize_type) {
2047 otmp->record_achieve_special = MINES_PRIZE;
2048 /* prevent stacking; cleared when achievement is recorded */
2050 if (++mines_prize_count > 1)
2051 impossible(prize_warning, "mines end");
2053 } else if (Is_sokoend_level(&u.uz)) {
2054 if (otmp->otyp == iflags.soko_prize_type1) {
2055 otmp->record_achieve_special = SOKO_PRIZE1;
2056 otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack */
2057 if (++soko_prize_count > 1)
2058 impossible(prize_warning, "sokoban end");
2059 } else if (otmp->otyp == iflags.soko_prize_type2) {
2060 otmp->record_achieve_special = SOKO_PRIZE2;
2061 otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack */
2062 if (++soko_prize_count > 1)
2063 impossible(prize_warning, "sokoban end");
2071 begin_burn(otmp, FALSE);
2077 (void) bury_an_obj(otmp, &dealloced);
2078 if (dealloced && container_idx) {
2079 container_obj[container_idx - 1] = NULL;
2085 * Create an altar in a room.
2088 create_altar(a, croom)
2090 struct mkroom *croom;
2092 schar sproom, x = -1, y = -1;
2094 boolean croom_is_temple = TRUE;
2098 get_free_room_loc(&x, &y, croom, a->coord);
2099 if (croom->rtype != TEMPLE)
2100 croom_is_temple = FALSE;
2102 get_location_coord(&x, &y, DRY, croom, a->coord);
2103 if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
2104 croom = &rooms[sproom - ROOMOFFSET];
2106 croom_is_temple = FALSE;
2109 /* check for existing features */
2110 oldtyp = levl[x][y].typ;
2111 if (oldtyp == STAIRS || oldtyp == LADDER)
2114 /* Is the alignment random ?
2115 * If so, it's an 80% chance that the altar will be co-aligned.
2117 * The alignment is encoded as amask values instead of alignment
2118 * values to avoid conflicting with the rest of the encoding,
2119 * shared by many other parts of the special level code.
2121 amask = (a->align == AM_SPLEV_CO)
2122 ? Align2amask(u.ualignbase[A_ORIGINAL])
2123 : (a->align == AM_SPLEV_NONCO)
2124 ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL]))
2125 : (a->align == -(MAX_REGISTERS + 1))
2127 : (a->align < 0 ? ralign[-a->align - 1] : a->align);
2129 levl[x][y].typ = ALTAR;
2130 levl[x][y].altarmask = amask;
2133 a->shrine = rn2(2); /* handle random case */
2135 if (!croom_is_temple || !a->shrine)
2138 if (a->shrine) { /* Is it a shrine or sanctum? */
2139 priestini(&u.uz, croom, x, y, (a->shrine > 1));
2140 levl[x][y].altarmask |= AM_SHRINE;
2141 level.flags.has_temple = TRUE;
2146 replace_terrain(terr, croom)
2147 replaceterrain *terr;
2148 struct mkroom *croom;
2150 schar x, y, x1, y1, x2, y2;
2152 if (terr->toter >= MAX_TYPE)
2157 get_location(&x1, &y1, ANY_LOC, croom);
2161 get_location(&x2, &y2, ANY_LOC, croom);
2163 for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++)
2164 for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++)
2165 if (levl[x][y].typ == terr->fromter && rn2(100) < terr->chance) {
2166 SET_TYPLIT(x, y, terr->toter, terr->tolit);
2171 * Search for a door in a room on a specified wall.
2174 search_door(croom, x, y, wall, cnt)
2175 struct mkroom *croom;
2209 dx = dy = xx = yy = 0;
2210 panic("search_door: Bad wall!");
2213 while (xx <= croom->hx + 1 && yy <= croom->hy + 1) {
2214 if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
2227 * Dig a corridor between two points.
2230 dig_corridor(org, dest, nxcor, ftyp, btyp)
2235 int dx = 0, dy = 0, dix, diy, cct;
2243 if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 || xx > COLNO - 1
2244 || tx > COLNO - 1 || yy > ROWNO - 1 || ty > ROWNO - 1) {
2245 debugpline4("dig_corridor: bad coords <%d,%d> <%d,%d>.",
2261 while (xx != tx || yy != ty) {
2262 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
2263 if (cct++ > 500 || (nxcor && !rn2(35)))
2269 if (xx >= COLNO - 1 || xx <= 0 || yy <= 0 || yy >= ROWNO - 1)
2270 return FALSE; /* impossible */
2272 crm = &levl[xx][yy];
2273 if (crm->typ == btyp) {
2274 if (ftyp != CORR || rn2(100)) {
2276 if (nxcor && !rn2(50))
2277 (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
2281 } else if (crm->typ != ftyp && crm->typ != SCORR) {
2286 /* find next corridor position */
2290 if ((dix > diy) && diy && !rn2(dix-diy+1)) {
2292 } else if ((diy > dix) && dix && !rn2(diy-dix+1)) {
2296 /* do we have to change direction ? */
2297 if (dy && dix > diy) {
2298 register int ddx = (xx > tx) ? -1 : 1;
2300 crm = &levl[xx + ddx][yy];
2301 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
2306 } else if (dx && diy > dix) {
2307 register int ddy = (yy > ty) ? -1 : 1;
2309 crm = &levl[xx][yy + ddy];
2310 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
2317 /* continue straight on? */
2318 crm = &levl[xx + dx][yy + dy];
2319 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
2322 /* no, what must we do now?? */
2325 dy = (ty < yy) ? -1 : 1;
2328 dx = (tx < xx) ? -1 : 1;
2330 crm = &levl[xx + dx][yy + dy];
2331 if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
2340 * Disgusting hack: since special levels have their rooms filled before
2341 * sorting the rooms, we have to re-arrange the speed values upstairs_room
2342 * and dnstairs_room after the rooms have been sorted. On normal levels,
2343 * stairs don't get created until _after_ sorting takes place.
2349 struct mkroom *croom;
2352 && !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx)
2353 && (dnstairs_room->ly <= ydnstair
2354 && ydnstair <= dnstairs_room->hy))) {
2355 for (i = 0; i < nroom; i++) {
2357 if ((croom->lx <= xdnstair && xdnstair <= croom->hx)
2358 && (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
2359 dnstairs_room = croom;
2364 panic("Couldn't find dnstair room in fix_stair_rooms!");
2367 && !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx)
2368 && (upstairs_room->ly <= yupstair
2369 && yupstair <= upstairs_room->hy))) {
2370 for (i = 0; i < nroom; i++) {
2372 if ((croom->lx <= xupstair && xupstair <= croom->hx)
2373 && (croom->ly <= yupstair && yupstair <= croom->hy)) {
2374 upstairs_room = croom;
2379 panic("Couldn't find upstair room in fix_stair_rooms!");
2384 * Corridors always start from a door. But it can end anywhere...
2385 * Basically we search for door coordinates or for endpoints coordinates
2386 * (from a distance).
2394 if (c->src.room == -1) {
2396 makecorridors(); /*makecorridors(c->src.door);*/
2400 if (!search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
2404 if (c->dest.room != -1) {
2405 if (!search_door(&rooms[c->dest.room], &dest.x, &dest.y, c->dest.wall,
2408 switch (c->src.wall) {
2422 switch (c->dest.wall) {
2436 (void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
2441 * Fill a room (shop, zoo, etc...) with appropriate stuff.
2444 fill_room(croom, prefilled)
2445 struct mkroom *croom;
2448 if (!croom || croom->rtype == OROOM)
2455 if (croom->rtype >= SHOPBASE) {
2456 stock_room(croom->rtype - SHOPBASE, croom);
2457 level.flags.has_shop = TRUE;
2461 switch (croom->rtype) {
2463 for (x = croom->lx; x <= croom->hx; x++)
2464 for (y = croom->ly; y <= croom->hy; y++)
2465 (void) mkgold((long) rn1(abs(depth(&u.uz)) * 100, 51),
2480 switch (croom->rtype) {
2482 level.flags.has_vault = TRUE;
2485 level.flags.has_zoo = TRUE;
2488 level.flags.has_court = TRUE;
2491 level.flags.has_morgue = TRUE;
2494 level.flags.has_beehive = TRUE;
2497 level.flags.has_barracks = TRUE;
2500 level.flags.has_temple = TRUE;
2503 level.flags.has_swamp = TRUE;
2514 struct mkroom *aroom;
2515 xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
2518 aroom = &subrooms[nsubroom];
2519 okroom = create_subroom(mkr, r->x, r->y, r->w, r->h, rtype, r->rlit);
2521 aroom = &rooms[nroom];
2522 okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, r->yalign,
2527 #ifdef SPECIALIZATION
2528 topologize(aroom, FALSE); /* set roomno */
2530 topologize(aroom); /* set roomno */
2532 aroom->needfill = r->filled;
2533 aroom->needjoining = r->joined;
2536 return (struct mkroom *) 0;
2540 * set lighting in a region that will not become a room.
2543 light_region(tmpregion)
2546 register boolean litstate = tmpregion->rlit ? 1 : 0;
2547 register int hiy = tmpregion->y2;
2549 register struct rm *lev;
2550 int lowy = tmpregion->y1;
2551 int lowx = tmpregion->x1, hix = tmpregion->x2;
2554 /* adjust region size for walls, but only if lighted */
2555 lowx = max(lowx - 1, 1);
2556 hix = min(hix + 1, COLNO - 1);
2557 lowy = max(lowy - 1, 0);
2558 hiy = min(hiy + 1, ROWNO - 1);
2560 for (x = lowx; x <= hix; x++) {
2561 lev = &levl[x][lowy];
2562 for (y = lowy; y <= hiy; y++) {
2563 if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
2564 lev->lit = litstate;
2571 wallify_map(x1, y1, x2, y2)
2574 int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
2578 y2 = min(y2, ROWNO - 1);
2579 x2 = min(x2, COLNO - 1);
2580 for (y = y1; y <= y2; y++) {
2581 lo_yy = (y > 0) ? y - 1 : 0;
2582 hi_yy = (y < y2) ? y + 1 : y2;
2583 for (x = x1; x <= x2; x++) {
2584 if (levl[x][y].typ != STONE)
2586 lo_xx = (x > 1) ? x - 1 : 1;
2587 hi_xx = (x < x2) ? x + 1 : x2;
2588 for (yy = lo_yy; yy <= hi_yy; yy++)
2589 for (xx = lo_xx; xx <= hi_xx; xx++)
2590 if (IS_ROOM(levl[xx][yy].typ)
2591 || levl[xx][yy].typ == CROSSWALL) {
2592 levl[x][y].typ = (yy != y) ? HWALL : VWALL;
2593 yy = hi_yy; /* end `yy' loop */
2594 break; /* end `xx' loop */
2601 * Select a random coordinate in the maze.
2603 * We want a place not 'touched' by the loader. That is, a place in
2604 * the maze outside every part of the special level.
2607 maze1xy(m, humidity)
2611 register int x, y, tryct = 2000;
2612 /* tryct: normally it won't take more than ten or so tries due
2613 to the circumstances under which we'll be called, but the
2614 `humidity' screening might drastically change the chances */
2617 x = rn1(x_maze_max - 3, 3);
2618 y = rn1(y_maze_max - 3, 3);
2620 break; /* give up */
2621 } while (!(x % 2) || !(y % 2) || SpLev_Map[x][y]
2622 || !is_ok_location((schar) x, (schar) y, humidity));
2624 m->x = (xchar) x, m->y = (xchar) y;
2628 * If there's a significant portion of maze unused by the special level,
2629 * we don't want it empty.
2631 * Makes the number of traps, monsters, etc. proportional
2632 * to the size of the maze.
2637 int mapcountmax, mapcount, mapfact;
2641 mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2642 mapcountmax = mapcountmax / 2;
2644 for (x = 2; x < x_maze_max; x++)
2645 for (y = 0; y < y_maze_max; y++)
2646 if (SpLev_Map[x][y])
2649 if ((mapcount > (int) (mapcountmax / 10))) {
2650 mapfact = (int) ((mapcount * 100L) / mapcountmax);
2651 for (x = rnd((int) (20 * mapfact) / 100); x; x--) {
2653 (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS, mm.x, mm.y,
2656 for (x = rnd((int) (12 * mapfact) / 100); x; x--) {
2658 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
2660 for (x = rn2(2); x; x--) {
2662 (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
2664 for (x = rnd((int) (12 * mapfact) / 100); x; x--) {
2666 (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
2668 for (x = rn2((int) (15 * mapfact) / 100); x; x--) {
2670 (void) mkgold(0L, mm.x, mm.y);
2672 for (x = rn2((int) (15 * mapfact) / 100); x; x--) {
2676 trytrap = rndtrap();
2677 if (sobj_at(BOULDER, mm.x, mm.y))
2678 while (is_pit(trytrap) || is_hole(trytrap))
2679 trytrap = rndtrap();
2680 (void) maketrap(mm.x, mm.y, trytrap);
2686 * special level loader
2689 sp_level_loader(fd, lvl)
2694 struct opvar *opdat;
2697 Fread((genericptr_t) & (lvl->n_opcodes), 1, sizeof(lvl->n_opcodes), fd);
2698 lvl->opcodes = (_opcode *) alloc(sizeof(_opcode) * (lvl->n_opcodes));
2700 while (n_opcode < lvl->n_opcodes) {
2701 Fread((genericptr_t) &lvl->opcodes[n_opcode].opcode, 1,
2702 sizeof(lvl->opcodes[n_opcode].opcode), fd);
2703 opcode = lvl->opcodes[n_opcode].opcode;
2707 if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES)
2708 panic("sp_level_loader: impossible opcode %i.", opcode);
2710 if (opcode == SPO_PUSH) {
2712 struct opvar *ov = (struct opvar *) alloc(sizeof(struct opvar));
2715 ov->spovartyp = SPO_NULL;
2717 Fread((genericptr_t) & (ov->spovartyp), 1, sizeof(ov->spovartyp),
2720 switch (ov->spovartyp) {
2725 case SPOVAR_MAPCHAR:
2729 Fread((genericptr_t) & (ov->vardata.l), 1,
2730 sizeof(ov->vardata.l), fd);
2732 case SPOVAR_VARIABLE:
2737 Fread((genericptr_t) &nsize, 1, sizeof(nsize), fd);
2738 opd = (char *) alloc(nsize + 1);
2741 Fread(opd, 1, nsize, fd);
2743 ov->vardata.str = opd;
2747 panic("sp_level_loader: unknown opvar type %i",
2752 lvl->opcodes[n_opcode].opdat = opdat;
2759 /* Frees the memory allocated for special level creation structs */
2764 static const char nhFunc[] = "sp_level_free";
2767 while (n_opcode < lvl->n_opcodes) {
2768 int opcode = lvl->opcodes[n_opcode].opcode;
2769 struct opvar *opdat = lvl->opcodes[n_opcode].opdat;
2771 if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES)
2772 panic("sp_level_free: unknown opcode %i", opcode);
2779 lvl->opcodes = NULL;
2784 splev_initlev(linit)
2787 switch (linit->init_style) {
2789 impossible("Unrecognized level init style.");
2793 case LVLINIT_SOLIDFILL:
2794 if (linit->lit == -1)
2795 linit->lit = rn2(2);
2796 lvlfill_solid(linit->filling, linit->lit);
2798 case LVLINIT_MAZEGRID:
2799 lvlfill_maze_grid(2, 0, x_maze_max, y_maze_max, linit->filling);
2805 if (linit->lit == -1)
2806 linit->lit = rn2(2);
2807 if (linit->filling > -1)
2808 lvlfill_solid(linit->filling, 0);
2809 linit->icedpools = icedpools;
2819 struct sp_frame *frame =
2820 (struct sp_frame *) alloc(sizeof(struct sp_frame));
2823 frame->variables = NULL;
2824 frame->n_opcode = execptr;
2825 frame->stack = (struct splevstack *) alloc(sizeof(struct splevstack));
2826 splev_stack_init(frame->stack);
2832 struct sp_frame *frame;
2837 splev_stack_done(frame->stack);
2838 frame->stack = NULL;
2840 if (frame->variables) {
2841 variable_list_del(frame->variables);
2842 frame->variables = NULL;
2848 spo_frame_push(coder)
2849 struct sp_coder *coder;
2851 struct sp_frame *tmpframe = frame_new(coder->frame->n_opcode);
2853 tmpframe->next = coder->frame;
2854 coder->frame = tmpframe;
2858 spo_frame_pop(coder)
2859 struct sp_coder *coder;
2861 if (coder->frame && coder->frame->next) {
2862 struct sp_frame *tmpframe = coder->frame->next;
2864 frame_del(coder->frame);
2865 coder->frame = tmpframe;
2866 coder->stack = coder->frame->stack;
2871 sp_code_jmpaddr(curpos, jmpaddr)
2872 long curpos, jmpaddr;
2874 return (curpos + jmpaddr);
2879 struct sp_coder *coder;
2881 static const char nhFunc[] = "spo_call";
2883 struct opvar *params;
2884 struct sp_frame *tmpframe;
2886 if (!OV_pop_i(addr) || !OV_pop_i(params))
2888 if (OV_i(params) < 0)
2891 tmpframe = frame_new(sp_code_jmpaddr(coder->frame->n_opcode,
2894 while (OV_i(params)-- > 0) {
2895 splev_stack_push(tmpframe->stack, splev_stack_getdat_any(coder));
2897 splev_stack_reverse(tmpframe->stack);
2900 tmpframe->next = coder->frame;
2901 coder->frame = tmpframe;
2909 struct sp_coder *coder;
2911 static const char nhFunc[] = "spo_return";
2912 struct opvar *params;
2914 if (!coder->frame || !coder->frame->next)
2915 panic("return: no frame.");
2916 if (!OV_pop_i(params))
2918 if (OV_i(params) < 0)
2921 while (OV_i(params)-- > 0) {
2922 splev_stack_push(coder->frame->next->stack,
2923 splev_stack_pop(coder->stack));
2927 if (coder->frame->next) {
2928 struct sp_frame *tmpframe = coder->frame->next;
2929 frame_del(coder->frame);
2930 coder->frame = tmpframe;
2931 coder->stack = coder->frame->stack;
2939 spo_end_moninvent(coder)
2940 struct sp_coder *coder UNUSED;
2942 if (invent_carrying_monster)
2943 m_dowear(invent_carrying_monster, TRUE);
2944 invent_carrying_monster = NULL;
2949 spo_pop_container(coder)
2950 struct sp_coder *coder UNUSED;
2952 if (container_idx > 0) {
2954 container_obj[container_idx] = NULL;
2960 struct sp_coder *coder;
2962 static const char nhFunc[] = "spo_message";
2973 old_n = lev_message ? (strlen(lev_message) + 1) : 0;
2976 levmsg = (char *) alloc(old_n + n + 1);
2978 levmsg[old_n - 1] = '\n';
2980 (void) memcpy((genericptr_t) levmsg, (genericptr_t) lev_message,
2982 (void) memcpy((genericptr_t) &levmsg[old_n], msg, n);
2983 levmsg[old_n + n] = '\0';
2985 lev_message = levmsg;
2991 struct sp_coder *coder;
2993 static const char nhFunc[] = "spo_monster";
2995 struct opvar *varparam;
2996 struct opvar *id, *mcoord, *has_inv;
2999 tmpmons.peaceful = -1;
3000 tmpmons.asleep = -1;
3001 tmpmons.name.str = (char *) 0;
3003 tmpmons.appear_as.str = (char *) 0;
3004 tmpmons.align = -MAX_REGISTERS - 2;
3007 tmpmons.cancelled = 0;
3008 tmpmons.revived = 0;
3010 tmpmons.fleeing = 0;
3011 tmpmons.blinded = 0;
3012 tmpmons.paralyzed = 0;
3013 tmpmons.stunned = 0;
3014 tmpmons.confused = 0;
3015 tmpmons.seentraps = 0;
3016 tmpmons.has_invent = 0;
3018 if (!OV_pop_i(has_inv))
3021 if (!OV_pop_i(varparam))
3024 while ((nparams++ < (SP_M_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT)
3025 && (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_M_V_END)) {
3026 struct opvar *parm = NULL;
3029 switch (OV_i(varparam)) {
3031 if ((OV_typ(parm) == SPOVAR_STRING) && !tmpmons.name.str)
3032 tmpmons.name.str = dupstr(OV_s(parm));
3035 if ((OV_typ(parm) == SPOVAR_INT) && !tmpmons.appear_as.str) {
3036 tmpmons.appear = OV_i(parm);
3039 tmpmons.appear_as.str = dupstr(OV_s(parm));
3043 if (OV_typ(parm) == SPOVAR_INT)
3044 tmpmons.asleep = OV_i(parm);
3047 if (OV_typ(parm) == SPOVAR_INT)
3048 tmpmons.align = OV_i(parm);
3050 case SP_M_V_PEACEFUL:
3051 if (OV_typ(parm) == SPOVAR_INT)
3052 tmpmons.peaceful = OV_i(parm);
3055 if (OV_typ(parm) == SPOVAR_INT)
3056 tmpmons.female = OV_i(parm);
3059 if (OV_typ(parm) == SPOVAR_INT)
3060 tmpmons.invis = OV_i(parm);
3062 case SP_M_V_CANCELLED:
3063 if (OV_typ(parm) == SPOVAR_INT)
3064 tmpmons.cancelled = OV_i(parm);
3066 case SP_M_V_REVIVED:
3067 if (OV_typ(parm) == SPOVAR_INT)
3068 tmpmons.revived = OV_i(parm);
3071 if (OV_typ(parm) == SPOVAR_INT)
3072 tmpmons.avenge = OV_i(parm);
3074 case SP_M_V_FLEEING:
3075 if (OV_typ(parm) == SPOVAR_INT)
3076 tmpmons.fleeing = OV_i(parm);
3078 case SP_M_V_BLINDED:
3079 if (OV_typ(parm) == SPOVAR_INT)
3080 tmpmons.blinded = OV_i(parm);
3082 case SP_M_V_PARALYZED:
3083 if (OV_typ(parm) == SPOVAR_INT)
3084 tmpmons.paralyzed = OV_i(parm);
3086 case SP_M_V_STUNNED:
3087 if (OV_typ(parm) == SPOVAR_INT)
3088 tmpmons.stunned = OV_i(parm);
3090 case SP_M_V_CONFUSED:
3091 if (OV_typ(parm) == SPOVAR_INT)
3092 tmpmons.confused = OV_i(parm);
3094 case SP_M_V_SEENTRAPS:
3095 if (OV_typ(parm) == SPOVAR_INT)
3096 tmpmons.seentraps = OV_i(parm);
3099 nparams = SP_M_V_END + 1;
3102 impossible("MONSTER with unknown variable param type!");
3106 if (OV_i(varparam) != SP_M_V_END) {
3107 opvar_free(varparam);
3112 if (!OV_pop_c(mcoord))
3113 panic("no monster coord?");
3115 if (!OV_pop_typ(id, SPOVAR_MONST))
3116 panic("no mon type");
3118 tmpmons.id = SP_MONST_PM(OV_i(id));
3119 tmpmons.class = SP_MONST_CLASS(OV_i(id));
3120 tmpmons.coord = OV_i(mcoord);
3121 tmpmons.has_invent = OV_i(has_inv);
3123 create_monster(&tmpmons, coder->croom);
3125 Free(tmpmons.name.str);
3126 Free(tmpmons.appear_as.str);
3129 opvar_free(has_inv);
3130 opvar_free(varparam);
3135 struct sp_coder *coder;
3137 static const char nhFunc[] = "spo_object";
3140 struct opvar *varparam;
3141 struct opvar *id, *containment;
3145 tmpobj.curse_state = -1;
3146 tmpobj.corpsenm = NON_PM;
3147 tmpobj.name.str = (char *) 0;
3153 tmpobj.trapped = -1;
3154 tmpobj.recharged = 0;
3158 tmpobj.coord = SP_COORD_PACK_RANDOM(0);
3160 if (!OV_pop_i(containment))
3163 if (!OV_pop_i(varparam))
3166 while ((nparams++ < (SP_O_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT)
3167 && (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_O_V_END)) {
3171 switch (OV_i(varparam)) {
3173 if ((OV_typ(parm) == SPOVAR_STRING) && !tmpobj.name.str)
3174 tmpobj.name.str = dupstr(OV_s(parm));
3176 case SP_O_V_CORPSENM:
3177 if (OV_typ(parm) == SPOVAR_MONST) {
3178 char monclass = SP_MONST_CLASS(OV_i(parm));
3179 int monid = SP_MONST_PM(OV_i(parm));
3181 if (monid >= LOW_PM && monid < NUMMONS) {
3182 tmpobj.corpsenm = monid;
3183 break; /* we're done! */
3185 struct permonst *pm = (struct permonst *) 0;
3187 if (def_char_to_monclass(monclass) != MAXMCLASSES) {
3188 pm = mkclass(def_char_to_monclass(monclass), G_NOGEN);
3193 tmpobj.corpsenm = monsndx(pm);
3198 if (OV_typ(parm) == SPOVAR_INT)
3199 tmpobj.curse_state = OV_i(parm);
3202 if (OV_typ(parm) == SPOVAR_INT)
3203 tmpobj.spe = OV_i(parm);
3206 if (OV_typ(parm) == SPOVAR_INT)
3207 tmpobj.quan = OV_i(parm);
3210 if (OV_typ(parm) == SPOVAR_INT)
3211 tmpobj.buried = OV_i(parm);
3214 if (OV_typ(parm) == SPOVAR_INT)
3215 tmpobj.lit = OV_i(parm);
3218 if (OV_typ(parm) == SPOVAR_INT)
3219 tmpobj.eroded = OV_i(parm);
3222 if (OV_typ(parm) == SPOVAR_INT)
3223 tmpobj.locked = OV_i(parm);
3225 case SP_O_V_TRAPPED:
3226 if (OV_typ(parm) == SPOVAR_INT)
3227 tmpobj.trapped = OV_i(parm);
3229 case SP_O_V_RECHARGED:
3230 if (OV_typ(parm) == SPOVAR_INT)
3231 tmpobj.recharged = OV_i(parm);
3234 if (OV_typ(parm) == SPOVAR_INT)
3235 tmpobj.invis = OV_i(parm);
3237 case SP_O_V_GREASED:
3238 if (OV_typ(parm) == SPOVAR_INT)
3239 tmpobj.greased = OV_i(parm);
3242 if (OV_typ(parm) == SPOVAR_INT)
3243 tmpobj.broken = OV_i(parm);
3246 if (OV_typ(parm) != SPOVAR_COORD)
3247 panic("no coord for obj?");
3248 tmpobj.coord = OV_i(parm);
3251 nparams = SP_O_V_END + 1;
3254 impossible("OBJECT with unknown variable param type!");
3258 if (OV_i(varparam) != SP_O_V_END) {
3259 opvar_free(varparam);
3264 if (!OV_pop_typ(id, SPOVAR_OBJ))
3265 panic("no obj type");
3267 tmpobj.id = SP_OBJ_TYP(OV_i(id));
3268 tmpobj.class = SP_OBJ_CLASS(OV_i(id));
3269 tmpobj.containment = OV_i(containment);
3271 quancnt = (tmpobj.id > STRANGE_OBJECT) ? tmpobj.quan : 0;
3274 create_object(&tmpobj, coder->croom);
3276 } while ((quancnt > 0) && ((tmpobj.id > STRANGE_OBJECT)
3277 && !objects[tmpobj.id].oc_merge));
3279 Free(tmpobj.name.str);
3280 opvar_free(varparam);
3282 opvar_free(containment);
3286 spo_level_flags(coder)
3287 struct sp_coder *coder;
3289 static const char nhFunc[] = "spo_level_flags";
3290 struct opvar *flagdata;
3293 if (!OV_pop_i(flagdata))
3295 lflags = OV_i(flagdata);
3297 if (lflags & NOTELEPORT)
3298 level.flags.noteleport = 1;
3299 if (lflags & HARDFLOOR)
3300 level.flags.hardfloor = 1;
3301 if (lflags & NOMMAP)
3302 level.flags.nommap = 1;
3303 if (lflags & SHORTSIGHTED)
3304 level.flags.shortsighted = 1;
3305 if (lflags & ARBOREAL)
3306 level.flags.arboreal = 1;
3307 if (lflags & MAZELEVEL)
3308 level.flags.is_maze_lev = 1;
3309 if (lflags & PREMAPPED)
3310 coder->premapped = TRUE;
3311 if (lflags & SHROUD)
3312 level.flags.hero_memory = 0;
3313 if (lflags & GRAVEYARD)
3314 level.flags.graveyard = 1;
3315 if (lflags & ICEDPOOLS)
3317 if (lflags & SOLIDIFY)
3318 coder->solidify = TRUE;
3319 if (lflags & CORRMAZE)
3320 level.flags.corrmaze = TRUE;
3321 if (lflags & CHECK_INACCESSIBLES)
3322 coder->check_inaccessibles = TRUE;
3324 opvar_free(flagdata);
3328 spo_initlevel(coder)
3329 struct sp_coder *coder;
3331 static const char nhFunc[] = "spo_initlevel";
3333 struct opvar *init_style, *fg, *bg, *smoothed, *joined, *lit, *walled,
3336 if (!OV_pop_i(fg) || !OV_pop_i(bg) || !OV_pop_i(smoothed)
3337 || !OV_pop_i(joined) || !OV_pop_i(lit) || !OV_pop_i(walled)
3338 || !OV_pop_i(filling) || !OV_pop_i(init_style))
3341 splev_init_present = TRUE;
3343 init_lev.init_style = OV_i(init_style);
3344 init_lev.fg = OV_i(fg);
3345 init_lev.bg = OV_i(bg);
3346 init_lev.smoothed = OV_i(smoothed);
3347 init_lev.joined = OV_i(joined);
3348 init_lev.lit = OV_i(lit);
3349 init_lev.walled = OV_i(walled);
3350 init_lev.filling = OV_i(filling);
3352 coder->lvl_is_joined = OV_i(joined);
3354 splev_initlev(&init_lev);
3356 opvar_free(init_style);
3359 opvar_free(smoothed);
3363 opvar_free(filling);
3367 spo_engraving(coder)
3368 struct sp_coder *coder;
3370 static const char nhFunc[] = "spo_engraving";
3371 struct opvar *etyp, *txt, *ecoord;
3374 if (!OV_pop_i(etyp) || !OV_pop_s(txt) || !OV_pop_c(ecoord))
3377 get_location_coord(&x, &y, DRY, coder->croom, OV_i(ecoord));
3378 make_engr_at(x, y, OV_s(txt), 0L, OV_i(etyp));
3386 spo_mineralize(coder)
3387 struct sp_coder *coder;
3389 static const char nhFunc[] = "spo_mineralize";
3390 struct opvar *kelp_pool, *kelp_moat, *gold_prob, *gem_prob;
3392 if (!OV_pop_i(gem_prob) || !OV_pop_i(gold_prob) || !OV_pop_i(kelp_moat)
3393 || !OV_pop_i(kelp_pool))
3396 mineralize(OV_i(kelp_pool), OV_i(kelp_moat), OV_i(gold_prob),
3397 OV_i(gem_prob), TRUE);
3399 opvar_free(gem_prob);
3400 opvar_free(gold_prob);
3401 opvar_free(kelp_moat);
3402 opvar_free(kelp_pool);
3407 struct sp_coder *coder;
3409 static const char nhFunc[] = "spo_room";
3411 if (coder->n_subroom > MAX_NESTED_ROOMS) {
3412 panic("Too deeply nested rooms?!");
3414 struct opvar *rflags, *h, *w, *yalign, *xalign, *y, *x, *rlit,
3417 struct mkroom *tmpcr;
3419 if (!OV_pop_i(h) || !OV_pop_i(w) || !OV_pop_i(y) || !OV_pop_i(x)
3420 || !OV_pop_i(yalign) || !OV_pop_i(xalign) || !OV_pop_i(rflags)
3421 || !OV_pop_i(rlit) || !OV_pop_i(chance) || !OV_pop_i(rtype))
3424 tmproom.x = OV_i(x);
3425 tmproom.y = OV_i(y);
3426 tmproom.w = OV_i(w);
3427 tmproom.h = OV_i(h);
3428 tmproom.xalign = OV_i(xalign);
3429 tmproom.yalign = OV_i(yalign);
3430 tmproom.rtype = OV_i(rtype);
3431 tmproom.chance = OV_i(chance);
3432 tmproom.rlit = OV_i(rlit);
3433 tmproom.filled = (OV_i(rflags) & (1 << 0));
3434 /*tmproom.irregular = (OV_i(rflags) & (1 << 1));*/
3435 tmproom.joined = !(OV_i(rflags) & (1 << 2));
3448 if (!coder->failed_room[coder->n_subroom - 1]) {
3449 tmpcr = build_room(&tmproom, coder->croom);
3451 coder->tmproomlist[coder->n_subroom] = tmpcr;
3452 coder->failed_room[coder->n_subroom] = FALSE;
3456 } /* failed to create parent room, so fail this too */
3458 coder->tmproomlist[coder->n_subroom] = (struct mkroom *) 0;
3459 coder->failed_room[coder->n_subroom] = TRUE;
3465 struct sp_coder *coder;
3467 if (coder->n_subroom > 1) {
3469 coder->tmproomlist[coder->n_subroom] = NULL;
3470 coder->failed_room[coder->n_subroom] = TRUE;
3472 /* no subroom, get out of top-level room */
3473 /* Need to ensure xstart/ystart/xsize/ysize have something sensible,
3474 in case there's some stuff to be created outside the outermost
3478 if (xsize <= 1 && ysize <= 1) {
3489 struct sp_coder *coder;
3491 static const char nhFunc[] = "spo_stair";
3493 struct opvar *up, *scoord;
3494 struct trap *badtrap;
3496 if (!OV_pop_i(up) || !OV_pop_c(scoord))
3499 get_location_coord(&x, &y, DRY, coder->croom, OV_i(scoord));
3500 if ((badtrap = t_at(x, y)) != 0)
3502 mkstairs(x, y, (char) OV_i(up), coder->croom);
3503 SpLev_Map[x][y] = 1;
3511 struct sp_coder *coder;
3513 static const char nhFunc[] = "spo_ladder";
3515 struct opvar *up, *lcoord;
3517 if (!OV_pop_i(up) || !OV_pop_c(lcoord))
3520 get_location_coord(&x, &y, DRY, coder->croom, OV_i(lcoord));
3522 levl[x][y].typ = LADDER;
3523 SpLev_Map[x][y] = 1;
3527 levl[x][y].ladder = LA_UP;
3531 levl[x][y].ladder = LA_DOWN;
3539 struct sp_coder *coder;
3541 static const char nhFunc[] = "spo_grave";
3542 struct opvar *gcoord, *typ, *txt;
3545 if (!OV_pop_i(typ) || !OV_pop_s(txt) || !OV_pop_c(gcoord))
3548 get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord));
3550 if (isok(x, y) && !t_at(x, y)) {
3551 levl[x][y].typ = GRAVE;
3552 switch (OV_i(typ)) {
3554 make_grave(x, y, OV_s(txt));
3557 make_grave(x, y, NULL);
3572 struct sp_coder *coder;
3574 static const char nhFunc[] = "spo_altar";
3575 struct opvar *al, *shrine, *acoord;
3578 if (!OV_pop_i(al) || !OV_pop_i(shrine) || !OV_pop_c(acoord))
3581 tmpaltar.coord = OV_i(acoord);
3582 tmpaltar.align = OV_i(al);
3583 tmpaltar.shrine = OV_i(shrine);
3585 create_altar(&tmpaltar, coder->croom);
3594 struct sp_coder *coder;
3596 static const char nhFunc[] = "spo_trap";
3598 struct opvar *tcoord;
3601 if (!OV_pop_i(type) || !OV_pop_c(tcoord))
3604 tmptrap.coord = OV_i(tcoord);
3605 tmptrap.type = OV_i(type);
3607 create_trap(&tmptrap, coder->croom);
3614 struct sp_coder *coder;
3616 static const char nhFunc[] = "spo_gold";
3617 struct opvar *gcoord, *amt;
3621 if (!OV_pop_c(gcoord) || !OV_pop_i(amt))
3624 get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord));
3627 mkgold(amount, x, y);
3634 struct sp_coder *coder;
3636 static const char nhFunc[] = "spo_corridor";
3637 struct opvar *deswall, *desdoor, *desroom, *srcwall, *srcdoor, *srcroom;
3640 if (!OV_pop_i(deswall) || !OV_pop_i(desdoor) || !OV_pop_i(desroom)
3641 || !OV_pop_i(srcwall) || !OV_pop_i(srcdoor) || !OV_pop_i(srcroom))
3644 tc.src.room = OV_i(srcroom);
3645 tc.src.door = OV_i(srcdoor);
3646 tc.src.wall = OV_i(srcwall);
3647 tc.dest.room = OV_i(desroom);
3648 tc.dest.door = OV_i(desdoor);
3649 tc.dest.wall = OV_i(deswall);
3651 create_corridor(&tc);
3653 opvar_free(deswall);
3654 opvar_free(desdoor);
3655 opvar_free(desroom);
3656 opvar_free(srcwall);
3657 opvar_free(srcdoor);
3658 opvar_free(srcroom);
3662 selection_opvar(nbuf)
3666 char buf[(COLNO * ROWNO) + 1];
3669 (void) memset(buf, 1, sizeof(buf));
3670 buf[(COLNO * ROWNO)] = '\0';
3671 ov = opvar_new_str(buf);
3673 ov = opvar_new_str(nbuf);
3675 ov->spovartyp = SPOVAR_SEL;
3680 selection_getpoint(x, y, ov)
3684 if (!ov || ov->spovartyp != SPOVAR_SEL)
3686 if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
3689 return (ov->vardata.str[COLNO * y + x] - 1);
3693 selection_setpoint(x, y, ov, c)
3698 if (!ov || ov->spovartyp != SPOVAR_SEL)
3700 if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
3703 ov->vardata.str[COLNO * y + x] = (char) (c + 1);
3713 ov = selection_opvar((char *) 0);
3717 for (x = 0; x < COLNO; x++)
3718 for (y = 0; y < ROWNO; y++)
3719 if (!selection_getpoint(x, y, s))
3720 selection_setpoint(x, y, ov, 1);
3726 selection_logical_oper(s1, s2, oper)
3727 struct opvar *s1, *s2;
3733 ov = selection_opvar((char *) 0);
3737 for (x = 0; x < COLNO; x++)
3738 for (y = 0; y < ROWNO; y++) {
3742 if (selection_getpoint(x, y, s1)
3743 || selection_getpoint(x, y, s2))
3744 selection_setpoint(x, y, ov, 1);
3747 if (selection_getpoint(x, y, s1)
3748 && selection_getpoint(x, y, s2))
3749 selection_setpoint(x, y, ov, 1);
3758 selection_filter_mapchar(ov, mc)
3765 struct opvar *ret = selection_opvar((char *) 0);
3767 if (!ov || !mc || !ret)
3769 mapc = SP_MAPCHAR_TYP(OV_i(mc));
3770 lit = SP_MAPCHAR_LIT(OV_i(mc));
3771 for (x = 0; x < COLNO; x++)
3772 for (y = 0; y < ROWNO; y++)
3773 if (selection_getpoint(x, y, ov) && (levl[x][y].typ == mapc)) {
3777 selection_setpoint(x, y, ret, 1);
3780 selection_setpoint(x, y, ret, rn2(2));
3784 if (levl[x][y].lit == lit)
3785 selection_setpoint(x, y, ret, 1);
3793 selection_filter_percent(ov, percent)
3801 for (x = 0; x < COLNO; x++)
3802 for (y = 0; y < ROWNO; y++)
3803 if (selection_getpoint(x, y, ov) && (rn2(100) >= percent))
3804 selection_setpoint(x, y, ov, 0);
3808 selection_rndcoord(ov, x, y, removeit)
3817 for (dx = 0; dx < COLNO; dx++)
3818 for (dy = 0; dy < ROWNO; dy++)
3819 if (isok(dx, dy) && selection_getpoint(dx, dy, ov))
3824 for (dx = 0; dx < COLNO; dx++)
3825 for (dy = 0; dy < ROWNO; dy++)
3826 if (isok(dx, dy) && selection_getpoint(dx, dy, ov)) {
3830 if (removeit) selection_setpoint(dx, dy, ov, 0);
3841 selection_do_grow(ov, dir)
3846 char tmp[COLNO][ROWNO];
3848 if (ov->spovartyp != SPOVAR_SEL)
3853 (void) memset(tmp, 0, sizeof tmp);
3855 for (x = 1; x < COLNO; x++)
3856 for (y = 0; y < ROWNO; y++) {
3857 /* note: dir is a mask of multiple directions, but the only
3858 way to specify diagonals is by including the two adjacent
3859 orthogonal directions, which effectively specifies three-
3860 way growth [WEST|NORTH => WEST plus WEST|NORTH plus NORTH] */
3861 if (((dir & W_WEST) && selection_getpoint(x + 1, y, ov))
3862 || (((dir & (W_WEST | W_NORTH)) == (W_WEST | W_NORTH))
3863 && selection_getpoint(x + 1, y + 1, ov))
3864 || ((dir & W_NORTH) && selection_getpoint(x, y + 1, ov))
3865 || (((dir & (W_NORTH | W_EAST)) == (W_NORTH | W_EAST))
3866 && selection_getpoint(x - 1, y + 1, ov))
3867 || ((dir & W_EAST) && selection_getpoint(x - 1, y, ov))
3868 || (((dir & (W_EAST | W_SOUTH)) == (W_EAST | W_SOUTH))
3869 && selection_getpoint(x - 1, y - 1, ov))
3870 || ((dir & W_SOUTH) && selection_getpoint(x, y - 1, ov))
3871 || (((dir & (W_SOUTH | W_WEST)) == (W_SOUTH | W_WEST))
3872 && selection_getpoint(x + 1, y - 1, ov))) {
3877 for (x = 1; x < COLNO; x++)
3878 for (y = 0; y < ROWNO; y++)
3880 selection_setpoint(x, y, ov, 1);
3883 STATIC_VAR int FDECL((*selection_flood_check_func), (int, int));
3884 STATIC_VAR schar floodfillchk_match_under_typ;
3887 set_selection_floodfillchk(f)
3888 int FDECL((*f), (int, int));
3890 selection_flood_check_func = f;
3894 floodfillchk_match_under(x,y)
3897 return (floodfillchk_match_under_typ == levl[x][y].typ);
3901 floodfillchk_match_accessible(x, y)
3904 return (ACCESSIBLE(levl[x][y].typ)
3905 || levl[x][y].typ == SDOOR
3906 || levl[x][y].typ == SCORR);
3909 /* check whethere <x,y> is already in xs[],ys[] */
3911 sel_flood_havepoint(x, y, xs, ys, n)
3916 xchar xx = (xchar) x, yy = (xchar) y;
3920 if (xs[n] == xx && ys[n] == yy)
3927 selection_floodfill(ov, x, y, diagonals)
3932 static const char nhFunc[] = "selection_floodfill";
3933 struct opvar *tmp = selection_opvar((char *) 0);
3934 #define SEL_FLOOD_STACK (COLNO * ROWNO)
3935 #define SEL_FLOOD(nx, ny) \
3937 if (idx < SEL_FLOOD_STACK) { \
3942 panic(floodfill_stack_overrun); \
3944 #define SEL_FLOOD_CHKDIR(mx, my, sel) \
3946 if (isok((mx), (my)) \
3947 && (*selection_flood_check_func)((mx), (my)) \
3948 && !selection_getpoint((mx), (my), (sel)) \
3949 && !sel_flood_havepoint((mx), (my), dx, dy, idx)) \
3950 SEL_FLOOD((mx), (my)); \
3952 static const char floodfill_stack_overrun[] = "floodfill stack overrun";
3954 xchar dx[SEL_FLOOD_STACK];
3955 xchar dy[SEL_FLOOD_STACK];
3957 if (selection_flood_check_func == (int FDECL((*), (int, int))) 0) {
3967 selection_setpoint(x, y, ov, 1);
3968 selection_setpoint(x, y, tmp, 1);
3970 SEL_FLOOD_CHKDIR((x + 1), y, tmp);
3971 SEL_FLOOD_CHKDIR((x - 1), y, tmp);
3972 SEL_FLOOD_CHKDIR(x, (y + 1), tmp);
3973 SEL_FLOOD_CHKDIR(x, (y - 1), tmp);
3975 SEL_FLOOD_CHKDIR((x + 1), (y + 1), tmp);
3976 SEL_FLOOD_CHKDIR((x - 1), (y - 1), tmp);
3977 SEL_FLOOD_CHKDIR((x - 1), (y + 1), tmp);
3978 SEL_FLOOD_CHKDIR((x + 1), (y - 1), tmp);
3982 #undef SEL_FLOOD_STACK
3983 #undef SEL_FLOOD_CHKDIR
3987 /* McIlroy's Ellipse Algorithm */
3989 selection_do_ellipse(ov, xc, yc, a, b, filled)
3991 int xc, yc, a, b, filled;
3992 { /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
3994 long a2 = (long) a * a, b2 = (long) b * b;
3995 long crit1 = -(a2 / 4 + a % 2 + b2);
3996 long crit2 = -(b2 / 4 + b % 2 + a2);
3997 long crit3 = -(b2 / 4 + b % 2);
3998 long t = -a2 * y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
3999 long dxt = 2 * b2 * x, dyt = -2 * a2 * y;
4000 long d2xt = 2 * b2, d2yt = 2 * a2;
4010 while (y >= 0 && x <= a) {
4011 selection_setpoint(xc + x, yc + y, ov, 1);
4012 if (x != 0 || y != 0)
4013 selection_setpoint(xc - x, yc - y, ov, 1);
4014 if (x != 0 && y != 0) {
4015 selection_setpoint(xc + x, yc - y, ov, 1);
4016 selection_setpoint(xc - x, yc + y, ov, 1);
4018 if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
4019 || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
4023 } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
4037 while (y >= 0 && x <= a) {
4038 if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
4039 || t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
4044 } else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
4045 for (i = 0; i < width; i++)
4046 selection_setpoint(xc - x + i, yc - y, ov, 1);
4048 for (i = 0; i < width; i++)
4049 selection_setpoint(xc - x + i, yc + y, ov, 1);
4054 for (i = 0; i < width; i++)
4055 selection_setpoint(xc - x + i, yc - y, ov, 1);
4057 for (i = 0; i < width; i++)
4058 selection_setpoint(xc - x + i, yc + y, ov, 1);
4071 /* distance from line segment (x1,y1, x2,y2) to point (x3,y3) */
4073 line_dist_coord(x1, y1, x2, y2, x3, y3)
4074 long x1, y1, x2, y2, x3, y3;
4078 long s = px * px + py * py;
4079 long x, y, dx, dy, dist = 0;
4082 if (x1 == x2 && y1 == y2)
4083 return isqrt(dist2(x1, y1, x3, y3));
4085 lu = ((x3 - x1) * px + (y3 - y1) * py) / (float) s;
4095 dist = isqrt(dx * dx + dy * dy);
4101 selection_do_gradient(ov, x, y, x2, y2, gtyp, mind, maxd, limit)
4103 long x, y, x2, y2, gtyp, mind, maxd, limit;
4119 case SEL_GRADIENT_RADIAL: {
4120 for (dx = 0; dx < COLNO; dx++)
4121 for (dy = 0; dy < ROWNO; dy++) {
4122 long d0 = line_dist_coord(x, y, x2, y2, dx, dy);
4123 if (d0 >= mind && (!limit || d0 <= maxd)) {
4124 if (d0 - mind > rn2(dofs))
4125 selection_setpoint(dx, dy, ov, 1);
4130 case SEL_GRADIENT_SQUARE: {
4131 for (dx = 0; dx < COLNO; dx++)
4132 for (dy = 0; dy < ROWNO; dy++) {
4133 long d1 = line_dist_coord(x, y, x2, y2, x, dy);
4134 long d2 = line_dist_coord(x, y, x2, y2, dx, y);
4135 long d3 = line_dist_coord(x, y, x2, y2, x2, dy);
4136 long d4 = line_dist_coord(x, y, x2, y2, dx, y2);
4137 long d5 = line_dist_coord(x, y, x2, y2, dx, dy);
4138 long d0 = min(d5, min(max(d1, d2), max(d3, d4)));
4140 if (d0 >= mind && (!limit || d0 <= maxd)) {
4141 if (d0 - mind > rn2(dofs))
4142 selection_setpoint(dx, dy, ov, 1);
4150 /* bresenham line algo */
4152 selection_do_line(x1, y1, x2, y2, ov)
4153 schar x1, y1, x2, y2;
4156 int d0, dx, dy, ai, bi, xi, yi;
4174 selection_setpoint(x1, y1, ov, 1);
4187 selection_setpoint(x1, y1, ov, 1);
4200 selection_setpoint(x1, y1, ov, 1);
4206 selection_do_randline(x1, y1, x2, y2, rough, rec, ov)
4207 schar x1, y1, x2, y2, rough, rec;
4217 if ((x2 == x1) && (y2 == y1)) {
4218 selection_setpoint(x1, y1, ov, 1);
4222 if (rough > max(abs(x2 - x1), abs(y2 - y1)))
4223 rough = max(abs(x2 - x1), abs(y2 - y1));
4226 mx = ((x1 + x2) / 2);
4227 my = ((y1 + y2) / 2);
4230 dx = rn2(rough) - (rough / 2);
4231 dy = rn2(rough) - (rough / 2);
4232 mx = ((x1 + x2) / 2) + dx;
4233 my = ((y1 + y2) / 2) + dy;
4234 } while ((mx > COLNO - 1 || mx < 0 || my < 0 || my > ROWNO - 1));
4237 selection_setpoint(mx, my, ov, 1);
4239 rough = (rough * 2) / 3;
4243 selection_do_randline(x1, y1, mx, my, rough, rec, ov);
4244 selection_do_randline(mx, my, x2, y2, rough, rec, ov);
4248 selection_iterate(ov, func, arg)
4250 select_iter_func func;
4255 /* yes, this is very naive, but it's not _that_ expensive. */
4256 for (x = 0; x < COLNO; x++)
4257 for (y = 0; y < ROWNO; y++)
4258 if (selection_getpoint(x, y, ov))
4263 sel_set_ter(x, y, arg)
4269 terr = *(terrain *) arg;
4270 SET_TYPLIT(x, y, terr.ter, terr.tlit);
4271 /* handle doors and secret doors */
4272 if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
4273 if (levl[x][y].typ == SDOOR)
4274 levl[x][y].doormask = D_CLOSED;
4275 if (x && (IS_WALL(levl[x - 1][y].typ) || levl[x - 1][y].horizontal))
4276 levl[x][y].horizontal = 1;
4281 sel_set_feature(x, y, arg)
4285 if (IS_FURNITURE(levl[x][y].typ))
4287 levl[x][y].typ = (*(int *) arg);
4291 sel_set_door(dx, dy, arg)
4295 xchar typ = *(xchar *) arg;
4296 xchar x = dx, y = dy;
4298 if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR)
4299 levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR;
4300 if (typ & D_SECRET) {
4305 set_door_orientation(x, y); /* set/clear levl[x][y].horizontal */
4306 levl[x][y].doormask = typ;
4307 SpLev_Map[x][y] = 1;
4312 struct sp_coder *coder;
4314 static const char nhFunc[] = "spo_door";
4315 struct opvar *msk, *sel;
4318 if (!OV_pop_i(msk) || !OV_pop_typ(sel, SPOVAR_SEL))
4321 typ = OV_i(msk) == -1 ? rnddoor() : (xchar) OV_i(msk);
4323 selection_iterate(sel, sel_set_door, (genericptr_t) &typ);
4331 struct sp_coder *coder;
4333 static const char nhFunc[] = "spo_feature";
4337 if (!OV_pop_typ(sel, SPOVAR_SEL))
4340 switch (coder->opcode) {
4342 impossible("spo_feature called with wrong opcode %i.", coder->opcode);
4354 selection_iterate(sel, sel_set_feature, (genericptr_t) &typ);
4360 struct sp_coder *coder;
4362 static const char nhFunc[] = "spo_terrain";
4364 struct opvar *ter, *sel;
4366 if (!OV_pop_typ(ter, SPOVAR_MAPCHAR) || !OV_pop_typ(sel, SPOVAR_SEL))
4369 tmpterrain.ter = SP_MAPCHAR_TYP(OV_i(ter));
4370 tmpterrain.tlit = SP_MAPCHAR_LIT(OV_i(ter));
4371 selection_iterate(sel, sel_set_ter, (genericptr_t) &tmpterrain);
4378 spo_replace_terrain(coder)
4379 struct sp_coder *coder;
4381 static const char nhFunc[] = "spo_replace_terrain";
4383 struct opvar *reg, *from_ter, *to_ter, *chance;
4385 if (!OV_pop_i(chance) || !OV_pop_typ(to_ter, SPOVAR_MAPCHAR)
4386 || !OV_pop_typ(from_ter, SPOVAR_MAPCHAR) || !OV_pop_r(reg))
4389 rt.chance = OV_i(chance);
4390 rt.tolit = SP_MAPCHAR_LIT(OV_i(to_ter));
4391 rt.toter = SP_MAPCHAR_TYP(OV_i(to_ter));
4392 rt.fromter = SP_MAPCHAR_TYP(OV_i(from_ter));
4393 /* TODO: use SP_MAPCHAR_LIT(OV_i(from_ter)) too */
4394 rt.x1 = SP_REGION_X1(OV_i(reg));
4395 rt.y1 = SP_REGION_Y1(OV_i(reg));
4396 rt.x2 = SP_REGION_X2(OV_i(reg));
4397 rt.y2 = SP_REGION_Y2(OV_i(reg));
4399 replace_terrain(&rt, coder->croom);
4402 opvar_free(from_ter);
4408 generate_way_out_method(nx,ny, ov)
4412 static const char nhFunc[] = "generate_way_out_method";
4413 const int escapeitems[] = { PICK_AXE,
4418 RIN_TELEPORTATION };
4419 struct opvar *ov2 = selection_opvar((char *) 0), *ov3;
4423 selection_floodfill(ov2, nx, ny, TRUE);
4424 ov3 = opvar_clone(ov2);
4426 /* try to make a secret door */
4427 while (selection_rndcoord(ov3, &x, &y, TRUE)) {
4428 if (isok(x+1, y) && !selection_getpoint(x+1, y, ov)
4429 && IS_WALL(levl[x+1][y].typ)
4430 && isok(x+2, y) && selection_getpoint(x+2, y, ov)
4431 && ACCESSIBLE(levl[x+2][y].typ)) {
4432 levl[x+1][y].typ = SDOOR;
4435 if (isok(x-1, y) && !selection_getpoint(x-1, y, ov)
4436 && IS_WALL(levl[x-1][y].typ)
4437 && isok(x-2, y) && selection_getpoint(x-2, y, ov)
4438 && ACCESSIBLE(levl[x-2][y].typ)) {
4439 levl[x-1][y].typ = SDOOR;
4442 if (isok(x, y+1) && !selection_getpoint(x, y+1, ov)
4443 && IS_WALL(levl[x][y+1].typ)
4444 && isok(x, y+2) && selection_getpoint(x, y+2, ov)
4445 && ACCESSIBLE(levl[x][y+2].typ)) {
4446 levl[x][y+1].typ = SDOOR;
4449 if (isok(x, y-1) && !selection_getpoint(x, y-1, ov)
4450 && IS_WALL(levl[x][y-1].typ)
4451 && isok(x, y-2) && selection_getpoint(x, y-2, ov)
4452 && ACCESSIBLE(levl[x][y-2].typ)) {
4453 levl[x][y-1].typ = SDOOR;
4458 /* try to make a hole or a trapdoor */
4459 if (Can_fall_thru(&u.uz)) {
4461 ov3 = opvar_clone(ov2);
4462 while (selection_rndcoord(ov3, &x, &y, TRUE)) {
4463 if (maketrap(x,y, rn2(2) ? HOLE : TRAPDOOR))
4468 /* generate one of the escape items */
4469 if (selection_rndcoord(ov2, &x, &y, FALSE)) {
4470 mksobj_at(escapeitems[rn2(SIZE(escapeitems))], x, y, TRUE, FALSE);
4484 static const char nhFunc[] = "ensure_way_out";
4485 struct opvar *ov = selection_opvar((char *) 0);
4486 struct trap *ttmp = ftrap;
4490 set_selection_floodfillchk(floodfillchk_match_accessible);
4492 if (xupstair && !selection_getpoint(xupstair, yupstair, ov))
4493 selection_floodfill(ov, xupstair, yupstair, TRUE);
4494 if (xdnstair && !selection_getpoint(xdnstair, ydnstair, ov))
4495 selection_floodfill(ov, xdnstair, ydnstair, TRUE);
4496 if (xupladder && !selection_getpoint(xupladder, yupladder, ov))
4497 selection_floodfill(ov, xupladder, yupladder, TRUE);
4498 if (xdnladder && !selection_getpoint(xdnladder, ydnladder, ov))
4499 selection_floodfill(ov, xdnladder, ydnladder, TRUE);
4502 if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE
4503 || is_hole(ttmp->ttyp))
4504 && !selection_getpoint(ttmp->tx, ttmp->ty, ov))
4505 selection_floodfill(ov, ttmp->tx, ttmp->ty, TRUE);
4511 for (x = 0; x < COLNO; x++)
4512 for (y = 0; y < ROWNO; y++)
4513 if (ACCESSIBLE(levl[x][y].typ)
4514 && !selection_getpoint(x, y, ov)) {
4515 if (generate_way_out_method(x,y, ov))
4516 selection_floodfill(ov, x,y, TRUE);
4526 spo_levregion(coder)
4527 struct sp_coder *coder;
4529 static const char nhFunc[] = "spo_levregion";
4530 struct opvar *rname, *padding, *rtype, *del_islev, *dy2, *dx2, *dy1, *dx1,
4531 *in_islev, *iy2, *ix2, *iy1, *ix1;
4533 lev_region *tmplregion;
4535 if (!OV_pop_s(rname) || !OV_pop_i(padding) || !OV_pop_i(rtype)
4536 || !OV_pop_i(del_islev) || !OV_pop_i(dy2) || !OV_pop_i(dx2)
4537 || !OV_pop_i(dy1) || !OV_pop_i(dx1) || !OV_pop_i(in_islev)
4538 || !OV_pop_i(iy2) || !OV_pop_i(ix2) || !OV_pop_i(iy1)
4542 tmplregion = (lev_region *) alloc(sizeof(lev_region));
4544 tmplregion->inarea.x1 = OV_i(ix1);
4545 tmplregion->inarea.y1 = OV_i(iy1);
4546 tmplregion->inarea.x2 = OV_i(ix2);
4547 tmplregion->inarea.y2 = OV_i(iy2);
4549 tmplregion->delarea.x1 = OV_i(dx1);
4550 tmplregion->delarea.y1 = OV_i(dy1);
4551 tmplregion->delarea.x2 = OV_i(dx2);
4552 tmplregion->delarea.y2 = OV_i(dy2);
4554 tmplregion->in_islev = OV_i(in_islev);
4555 tmplregion->del_islev = OV_i(del_islev);
4556 tmplregion->rtype = OV_i(rtype);
4557 tmplregion->padding = OV_i(padding);
4558 tmplregion->rname.str = dupstr(OV_s(rname));
4560 if (!tmplregion->in_islev) {
4561 get_location(&tmplregion->inarea.x1, &tmplregion->inarea.y1, ANY_LOC,
4562 (struct mkroom *) 0);
4563 get_location(&tmplregion->inarea.x2, &tmplregion->inarea.y2, ANY_LOC,
4564 (struct mkroom *) 0);
4567 if (!tmplregion->del_islev) {
4568 get_location(&tmplregion->delarea.x1, &tmplregion->delarea.y1,
4569 ANY_LOC, (struct mkroom *) 0);
4570 get_location(&tmplregion->delarea.x2, &tmplregion->delarea.y2,
4571 ANY_LOC, (struct mkroom *) 0);
4574 /* realloc the lregion space to add the new one */
4575 lev_region *newl = (lev_region *) alloc(
4576 sizeof(lev_region) * (unsigned) (1 + num_lregions));
4578 (void) memcpy((genericptr_t) (newl), (genericptr_t) lregions,
4579 sizeof(lev_region) * num_lregions);
4585 lregions = (lev_region *) alloc(sizeof(lev_region));
4587 (void) memcpy(&lregions[num_lregions - 1], tmplregion,
4588 sizeof(lev_region));
4601 opvar_free(del_islev);
4602 opvar_free(in_islev);
4605 opvar_free(padding);
4610 struct sp_coder *coder;
4612 static const char nhFunc[] = "spo_region";
4613 struct opvar *rtype, *rlit, *rflags, *area;
4614 xchar dx1, dy1, dx2, dy2;
4615 register struct mkroom *troom;
4616 boolean prefilled, room_not_needed, irregular, joined;
4618 if (!OV_pop_i(rflags) || !OV_pop_i(rtype) || !OV_pop_i(rlit)
4622 prefilled = !(OV_i(rflags) & (1 << 0));
4623 irregular = (OV_i(rflags) & (1 << 1));
4624 joined = !(OV_i(rflags) & (1 << 2));
4626 if (OV_i(rtype) > MAXRTYPE) {
4627 OV_i(rtype) -= MAXRTYPE + 1;
4634 (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
4636 dx1 = SP_REGION_X1(OV_i(area));
4637 dy1 = SP_REGION_Y1(OV_i(area));
4638 dx2 = SP_REGION_X2(OV_i(area));
4639 dy2 = SP_REGION_Y2(OV_i(area));
4641 get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0);
4642 get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0);
4644 /* for an ordinary room, `prefilled' is a flag to force
4645 an actual room to be created (such rooms are used to
4646 control placement of migrating monster arrivals) */
4647 room_not_needed = (OV_i(rtype) == OROOM && !irregular && !prefilled);
4648 if (room_not_needed || nroom >= MAXNROFROOMS) {
4650 if (!room_not_needed)
4651 impossible("Too many rooms on new level!");
4652 tmpregion.rlit = OV_i(rlit);
4657 light_region(&tmpregion);
4667 troom = &rooms[nroom];
4669 /* mark rooms that must be filled, but do it later */
4670 if (OV_i(rtype) != OROOM)
4671 troom->needfill = (prefilled ? 2 : 1);
4673 troom->needjoining = joined;
4676 min_rx = max_rx = dx1;
4677 min_ry = max_ry = dy1;
4678 smeq[nroom] = nroom;
4679 flood_fill_rm(dx1, dy1, nroom + ROOMOFFSET, OV_i(rlit), TRUE);
4680 add_room(min_rx, min_ry, max_rx, max_ry, FALSE, OV_i(rtype), TRUE);
4681 troom->rlit = OV_i(rlit);
4682 troom->irregular = TRUE;
4684 add_room(dx1, dy1, dx2, dy2, OV_i(rlit), OV_i(rtype), TRUE);
4685 #ifdef SPECIALIZATION
4686 topologize(troom, FALSE); /* set roomno */
4688 topologize(troom); /* set roomno */
4692 if (!room_not_needed) {
4693 if (coder->n_subroom > 1)
4694 impossible("region as subroom");
4696 coder->tmproomlist[coder->n_subroom] = troom;
4697 coder->failed_room[coder->n_subroom] = FALSE;
4709 spo_drawbridge(coder)
4710 struct sp_coder *coder;
4712 static const char nhFunc[] = "spo_drawbridge";
4715 struct opvar *dir, *db_open, *dcoord;
4717 if (!OV_pop_i(dir) || !OV_pop_i(db_open) || !OV_pop_c(dcoord))
4720 get_location_coord(&x, &y, DRY | WET | HOT, coder->croom, OV_i(dcoord));
4721 if ((dopen = OV_i(db_open)) == -1)
4723 if (!create_drawbridge(x, y, OV_i(dir), dopen ? TRUE : FALSE))
4724 impossible("Cannot create drawbridge.");
4725 SpLev_Map[x][y] = 1;
4728 opvar_free(db_open);
4734 struct sp_coder *coder;
4736 static const char nhFunc[] = "spo_mazewalk";
4738 struct opvar *ftyp, *fstocked, *fdir, *mcoord;
4741 if (!OV_pop_i(ftyp) || !OV_pop_i(fstocked) || !OV_pop_i(fdir)
4742 || !OV_pop_c(mcoord))
4747 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(mcoord));
4751 if (OV_i(ftyp) < 1) {
4752 OV_i(ftyp) = level.flags.corrmaze ? CORR : ROOM;
4755 /* don't use move() - it doesn't use W_NORTH, etc. */
4770 impossible("spo_mazewalk: Bad MAZEWALK direction");
4773 if (!IS_DOOR(levl[x][y].typ)) {
4774 levl[x][y].typ = OV_i(ftyp);
4775 levl[x][y].flags = 0;
4779 * We must be sure that the parity of the coordinates for
4780 * walkfrom() is odd. But we must also take into account
4781 * what direction was chosen.
4789 /* no need for IS_DOOR check; out of map bounds */
4790 levl[x][y].typ = OV_i(ftyp);
4791 levl[x][y].flags = 0;
4801 walkfrom(x, y, OV_i(ftyp));
4807 opvar_free(fstocked);
4812 spo_wall_property(coder)
4813 struct sp_coder *coder;
4815 static const char nhFunc[] = "spo_wall_property";
4817 xchar dx1, dy1, dx2, dy2;
4818 int wprop = (coder->opcode == SPO_NON_DIGGABLE)
4825 dx1 = SP_REGION_X1(OV_i(r));
4826 dy1 = SP_REGION_Y1(OV_i(r));
4827 dx2 = SP_REGION_X2(OV_i(r));
4828 dy2 = SP_REGION_Y2(OV_i(r));
4830 get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0);
4831 get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0);
4833 set_wall_property(dx1, dy1, dx2, dy2, wprop);
4839 spo_room_door(coder)
4840 struct sp_coder *coder;
4842 static const char nhFunc[] = "spo_room_door";
4843 struct opvar *wall, *secret, *mask, *pos;
4846 if (!OV_pop_i(wall) || !OV_pop_i(secret) || !OV_pop_i(mask)
4847 || !OV_pop_i(pos) || !coder->croom)
4850 tmpd.secret = OV_i(secret);
4851 tmpd.mask = OV_i(mask);
4852 tmpd.pos = OV_i(pos);
4853 tmpd.wall = OV_i(wall);
4855 create_door(&tmpd, coder->croom);
4865 sel_set_wallify(x, y, arg)
4867 genericptr_t arg UNUSED;
4869 wallify_map(x, y, x, y);
4874 struct sp_coder *coder;
4876 static const char nhFunc[] = "spo_wallify";
4877 struct opvar *typ, *r;
4878 int dx1, dy1, dx2, dy2;
4882 switch (OV_i(typ)) {
4887 dx1 = (xchar) SP_REGION_X1(OV_i(r));
4888 dy1 = (xchar) SP_REGION_Y1(OV_i(r));
4889 dx2 = (xchar) SP_REGION_X2(OV_i(r));
4890 dy2 = (xchar) SP_REGION_Y2(OV_i(r));
4891 wallify_map(dx1 < 0 ? (xstart - 1) : dx1,
4892 dy1 < 0 ? (ystart - 1) : dy1,
4893 dx2 < 0 ? (xstart + xsize + 1) : dx2,
4894 dy2 < 0 ? (ystart + ysize + 1) : dy2);
4897 if (!OV_pop_typ(r, SPOVAR_SEL))
4899 selection_iterate(r, sel_set_wallify, NULL);
4908 struct sp_coder *coder;
4910 static const char nhFunc[] = "spo_map";
4911 mazepart tmpmazepart;
4912 struct opvar *mpxs, *mpys, *mpmap, *mpa, *mpkeepr, *mpzalign;
4913 xchar halign, valign;
4914 xchar tmpxstart, tmpystart, tmpxsize, tmpysize;
4917 if (!OV_pop_i(mpxs) || !OV_pop_i(mpys) || !OV_pop_s(mpmap)
4918 || !OV_pop_i(mpkeepr) || !OV_pop_i(mpzalign) || !OV_pop_c(mpa))
4921 tmpmazepart.xsize = OV_i(mpxs);
4922 tmpmazepart.ysize = OV_i(mpys);
4923 tmpmazepart.zaligntyp = OV_i(mpzalign);
4925 upc = get_unpacked_coord(OV_i(mpa), ANY_LOC);
4926 tmpmazepart.halign = upc.x;
4927 tmpmazepart.valign = upc.y;
4934 halign = tmpmazepart.halign;
4935 valign = tmpmazepart.valign;
4936 xsize = tmpmazepart.xsize;
4937 ysize = tmpmazepart.ysize;
4938 switch (tmpmazepart.zaligntyp) {
4943 switch ((int) halign) {
4945 xstart = splev_init_present ? 1 : 3;
4948 xstart = 2 + ((x_maze_max - 2 - xsize) / 4);
4951 xstart = 2 + ((x_maze_max - 2 - xsize) / 2);
4954 xstart = 2 + ((x_maze_max - 2 - xsize) * 3 / 4);
4957 xstart = x_maze_max - xsize - 1;
4960 switch ((int) valign) {
4965 ystart = 2 + ((y_maze_max - 2 - ysize) / 2);
4968 ystart = y_maze_max - ysize - 1;
4977 if (!coder->croom) {
4980 xsize = COLNO - 1 - tmpmazepart.xsize;
4981 ysize = ROWNO - tmpmazepart.ysize;
4983 get_location_coord(&halign, &valign, ANY_LOC, coder->croom,
4985 xsize = tmpmazepart.xsize;
4986 ysize = tmpmazepart.ysize;
4991 if (ystart < 0 || ystart + ysize > ROWNO) {
4992 /* try to move the start a bit */
4993 ystart += (ystart > 0) ? -2 : 2;
4996 if (ystart < 0 || ystart + ysize > ROWNO)
4997 panic("reading special level with ysize too large");
4999 if (xsize <= 1 && ysize <= 1) {
5008 for (y = ystart; y < ystart + ysize; y++)
5009 for (x = xstart; x < xstart + xsize; x++) {
5010 mptyp = (mpmap->vardata.str[(y - ystart) * xsize
5011 + (x - xstart)] - 1);
5012 if (mptyp >= MAX_TYPE)
5014 levl[x][y].typ = mptyp;
5015 levl[x][y].lit = FALSE;
5016 /* clear out levl: load_common_data may set them */
5017 levl[x][y].flags = 0;
5018 levl[x][y].horizontal = 0;
5019 levl[x][y].roomno = 0;
5020 levl[x][y].edge = 0;
5021 SpLev_Map[x][y] = 1;
5023 * Set secret doors to closed (why not trapped too?). Set
5024 * the horizontal bit.
5026 if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
5027 if (levl[x][y].typ == SDOOR)
5028 levl[x][y].doormask = D_CLOSED;
5030 * If there is a wall to the left that connects to a
5031 * (secret) door, then it is horizontal. This does
5032 * not allow (secret) doors to be corners of rooms.
5034 if (x != xstart && (IS_WALL(levl[x - 1][y].typ)
5035 || levl[x - 1][y].horizontal))
5036 levl[x][y].horizontal = 1;
5037 } else if (levl[x][y].typ == HWALL
5038 || levl[x][y].typ == IRONBARS)
5039 levl[x][y].horizontal = 1;
5040 else if (levl[x][y].typ == LAVAPOOL)
5042 else if (splev_init_present && levl[x][y].typ == ICE)
5043 levl[x][y].icedpool = icedpools ? ICED_POOL : ICED_MOAT;
5045 if (coder->lvl_is_joined)
5046 remove_rooms(xstart, ystart, xstart + xsize, ystart + ysize);
5048 if (!OV_i(mpkeepr)) {
5059 opvar_free(mpkeepr);
5060 opvar_free(mpzalign);
5065 struct sp_coder *coder;
5068 static const char nhFunc[] = "spo_jmp";
5072 if (!OV_pop_i(tmpa))
5074 a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(tmpa) - 1));
5075 if ((a >= 0) && (a < lvl->n_opcodes) && (a != coder->frame->n_opcode))
5076 coder->frame->n_opcode = a;
5081 spo_conditional_jump(coder, lvl)
5082 struct sp_coder *coder;
5085 static const char nhFunc[] = "spo_conditional_jump";
5086 struct opvar *oa, *oc;
5090 if (!OV_pop_i(oa) || !OV_pop_i(oc))
5093 a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(oa) - 1));
5096 switch (coder->opcode) {
5098 impossible("spo_conditional_jump: illegal opcode");
5101 test = (c & SP_CPUFLAG_LT);
5104 test = (c & (SP_CPUFLAG_LT | SP_CPUFLAG_EQ));
5107 test = (c & SP_CPUFLAG_GT);
5110 test = (c & (SP_CPUFLAG_GT | SP_CPUFLAG_EQ));
5113 test = (c & SP_CPUFLAG_EQ);
5116 test = (c & ~SP_CPUFLAG_EQ);
5120 if ((test) && (a >= 0) && (a < lvl->n_opcodes)
5121 && (a != coder->frame->n_opcode))
5122 coder->frame->n_opcode = a;
5130 struct sp_coder *coder;
5132 static const char nhFunc[] = "spo_var_init";
5133 struct opvar *vname;
5134 struct opvar *arraylen;
5135 struct opvar *vvalue;
5136 struct splev_var *tmpvar;
5137 struct splev_var *tmp2;
5143 if (!vname || !arraylen)
5144 panic("no values for SPO_VAR_INIT");
5146 tmpvar = opvar_var_defined(coder, OV_s(vname));
5149 /* variable redefinition */
5150 if (OV_i(arraylen) < 0) {
5152 if (tmpvar->array_len) {
5153 idx = tmpvar->array_len;
5155 opvar_free(tmpvar->data.arrayvalues[idx]);
5157 Free(tmpvar->data.arrayvalues);
5159 opvar_free(tmpvar->data.value);
5161 tmpvar->data.arrayvalues = NULL;
5163 } else if (OV_i(arraylen)) {
5164 /* redefined array */
5165 idx = tmpvar->array_len;
5167 opvar_free(tmpvar->data.arrayvalues[idx]);
5169 Free(tmpvar->data.arrayvalues);
5170 tmpvar->data.arrayvalues = NULL;
5171 goto create_new_array;
5173 /* redefined single value */
5175 if (tmpvar->svtyp != vvalue->spovartyp)
5176 panic("redefining variable as different type");
5177 opvar_free(tmpvar->data.value);
5178 tmpvar->data.value = vvalue;
5179 tmpvar->array_len = 0;
5182 /* new variable definition */
5183 tmpvar = (struct splev_var *) alloc(sizeof(struct splev_var));
5184 tmpvar->next = coder->frame->variables;
5185 tmpvar->name = dupstr(OV_s(vname));
5186 coder->frame->variables = tmpvar;
5188 if (OV_i(arraylen) < 0) {
5192 tmp2 = opvar_var_defined(coder, OV_s(vvalue));
5194 panic("no copyable var");
5195 tmpvar->svtyp = tmp2->svtyp;
5196 tmpvar->array_len = tmp2->array_len;
5197 if (tmpvar->array_len) {
5198 idx = tmpvar->array_len;
5199 tmpvar->data.arrayvalues =
5200 (struct opvar **) alloc(sizeof(struct opvar *) * idx);
5202 tmpvar->data.arrayvalues[idx] =
5203 opvar_clone(tmp2->data.arrayvalues[idx]);
5206 tmpvar->data.value = opvar_clone(tmp2->data.value);
5209 } else if (OV_i(arraylen)) {
5212 idx = OV_i(arraylen);
5213 tmpvar->array_len = idx;
5214 tmpvar->data.arrayvalues =
5215 (struct opvar **) alloc(sizeof(struct opvar *) * idx);
5219 panic("no value for arrayvariable");
5220 tmpvar->data.arrayvalues[idx] = vvalue;
5222 tmpvar->svtyp = SPOVAR_ARRAY;
5224 /* new single value */
5227 panic("no value for variable");
5228 tmpvar->svtyp = OV_typ(vvalue);
5229 tmpvar->data.value = vvalue;
5230 tmpvar->array_len = 0;
5235 opvar_free(arraylen);
5241 opvar_array_length(coder)
5242 struct sp_coder *coder;
5244 static const char nhFunc[] = "opvar_array_length";
5245 struct opvar *vname;
5246 struct splev_var *tmp;
5252 vname = splev_stack_pop(coder->stack);
5255 if (vname->spovartyp != SPOVAR_VARIABLE)
5258 tmp = coder->frame->variables;
5260 if (!strcmp(tmp->name, OV_s(vname))) {
5261 if ((tmp->svtyp & SPOVAR_ARRAY)) {
5262 len = tmp->array_len;
5278 spo_shuffle_array(coder)
5279 struct sp_coder *coder;
5281 static const char nhFunc[] = "spo_shuffle_array";
5282 struct opvar *vname;
5283 struct splev_var *tmp;
5287 if (!OV_pop_s(vname))
5290 tmp = opvar_var_defined(coder, OV_s(vname));
5291 if (!tmp || (tmp->array_len < 1)) {
5295 for (i = tmp->array_len - 1; i > 0; i--) {
5296 if ((j = rn2(i + 1)) == i)
5298 tmp2 = tmp->data.arrayvalues[j];
5299 tmp->data.arrayvalues[j] = tmp->data.arrayvalues[i];
5300 tmp->data.arrayvalues[i] = tmp2;
5306 /* Special level coder, creates the special level from the sp_lev codes.
5307 * Does not free the allocated memory.
5313 static const char nhFunc[] = "sp_level_coder";
5314 unsigned long exec_opcodes = 0;
5316 long room_stack = 0;
5317 unsigned long max_execution = SPCODER_MAX_RUNTIME;
5318 struct sp_coder *coder =
5319 (struct sp_coder *) alloc(sizeof (struct sp_coder));
5321 coder->frame = frame_new(0);
5322 coder->stack = NULL;
5323 coder->premapped = FALSE;
5324 coder->solidify = FALSE;
5325 coder->check_inaccessibles = FALSE;
5326 coder->croom = NULL;
5327 coder->n_subroom = 1;
5328 coder->exit_script = FALSE;
5329 coder->lvl_is_joined = 0;
5331 splev_init_present = FALSE;
5333 /* achievement tracking; static init would suffice except we need to
5334 reset if #wizmakemap is used to recreate mines' end or sokoban end;
5335 once either level is created, these values can be forgotten */
5336 mines_prize_count = soko_prize_count = 0;
5339 char *met = nh_getenv("SPCODER_MAX_RUNTIME");
5341 if (met && met[0] == '1')
5342 max_execution = (1 << 30) - 1;
5345 for (tmpi = 0; tmpi <= MAX_NESTED_ROOMS; tmpi++) {
5346 coder->tmproomlist[tmpi] = (struct mkroom *) 0;
5347 coder->failed_room[tmpi] = FALSE;
5350 shuffle_alignments();
5352 for (tmpi = 0; tmpi < MAX_CONTAINMENT; tmpi++)
5353 container_obj[tmpi] = NULL;
5356 invent_carrying_monster = NULL;
5358 (void) memset((genericptr_t) &SpLev_Map[0][0], 0, sizeof SpLev_Map);
5360 level.flags.is_maze_lev = 0;
5367 while (coder->frame->n_opcode < lvl->n_opcodes && !coder->exit_script) {
5368 coder->opcode = lvl->opcodes[coder->frame->n_opcode].opcode;
5369 coder->opdat = lvl->opcodes[coder->frame->n_opcode].opdat;
5371 coder->stack = coder->frame->stack;
5373 if (exec_opcodes++ > max_execution) {
5374 impossible("Level script is taking too much time, stopping.");
5375 coder->exit_script = TRUE;
5378 if (coder->failed_room[coder->n_subroom - 1]
5379 && coder->opcode != SPO_ENDROOM && coder->opcode != SPO_ROOM
5380 && coder->opcode != SPO_SUBROOM)
5383 coder->croom = coder->tmproomlist[coder->n_subroom - 1];
5385 switch (coder->opcode) {
5389 coder->exit_script = TRUE;
5391 case SPO_FRAME_PUSH:
5392 spo_frame_push(coder);
5395 spo_frame_pop(coder);
5403 case SPO_END_MONINVENT:
5404 spo_end_moninvent(coder);
5406 case SPO_POP_CONTAINER:
5407 spo_pop_container(coder);
5410 struct opvar *ov = splev_stack_pop(coder->stack);
5416 splev_stack_push(coder->stack, opvar_clone(coder->opdat));
5427 case SPO_LEVEL_FLAGS:
5428 spo_level_flags(coder);
5431 spo_initlevel(coder);
5434 spo_engraving(coder);
5436 case SPO_MINERALIZE:
5437 spo_mineralize(coder);
5441 if (!coder->failed_room[coder->n_subroom - 1]) {
5447 if (coder->failed_room[coder->n_subroom - 1]) {
5483 spo_corridor(coder);
5488 case SPO_REPLACETERRAIN:
5489 spo_replace_terrain(coder);
5492 spo_levregion(coder);
5497 case SPO_DRAWBRIDGE:
5498 spo_drawbridge(coder);
5501 spo_mazewalk(coder);
5503 case SPO_NON_PASSWALL:
5504 case SPO_NON_DIGGABLE:
5505 spo_wall_property(coder);
5508 spo_room_door(coder);
5514 struct opvar *a = splev_stack_pop(coder->stack);
5516 splev_stack_push(coder->stack, opvar_clone(a));
5517 splev_stack_push(coder->stack, opvar_clone(a));
5527 splev_stack_push(coder->stack, a);
5536 splev_stack_push(coder->stack, a);
5539 case SPO_MATH_SIGN: {
5544 OV_i(a) = ((OV_i(a) < 0) ? -1 : ((OV_i(a) > 0) ? 1 : 0));
5545 splev_stack_push(coder->stack, a);
5548 case SPO_MATH_ADD: {
5549 struct opvar *a, *b;
5551 if (!OV_pop(b) || !OV_pop(a))
5553 if (OV_typ(b) == OV_typ(a)) {
5554 if (OV_typ(a) == SPOVAR_INT) {
5555 OV_i(a) = OV_i(a) + OV_i(b);
5556 splev_stack_push(coder->stack, a);
5558 } else if (OV_typ(a) == SPOVAR_STRING) {
5560 char *tmpbuf = (char *) alloc(strlen(OV_s(a))
5561 + strlen(OV_s(b)) + 1);
5563 (void) sprintf(tmpbuf, "%s%s", OV_s(a), OV_s(b));
5564 c = opvar_new_str(tmpbuf);
5565 splev_stack_push(coder->stack, c);
5570 splev_stack_push(coder->stack, a);
5572 impossible("adding weird types");
5575 splev_stack_push(coder->stack, a);
5577 impossible("adding different types");
5581 case SPO_MATH_SUB: {
5582 struct opvar *a, *b;
5584 if (!OV_pop_i(b) || !OV_pop_i(a))
5586 OV_i(a) = OV_i(a) - OV_i(b);
5587 splev_stack_push(coder->stack, a);
5591 case SPO_MATH_MUL: {
5592 struct opvar *a, *b;
5594 if (!OV_pop_i(b) || !OV_pop_i(a))
5596 OV_i(a) = OV_i(a) * OV_i(b);
5597 splev_stack_push(coder->stack, a);
5601 case SPO_MATH_DIV: {
5602 struct opvar *a, *b;
5604 if (!OV_pop_i(b) || !OV_pop_i(a))
5607 OV_i(a) = OV_i(a) / OV_i(b);
5611 splev_stack_push(coder->stack, a);
5615 case SPO_MATH_MOD: {
5616 struct opvar *a, *b;
5618 if (!OV_pop_i(b) || !OV_pop_i(a))
5621 OV_i(a) = OV_i(a) % OV_i(b);
5625 splev_stack_push(coder->stack, a);
5638 impossible("spo_cmp: no values in stack");
5641 if (OV_typ(a) != OV_typ(b)) {
5642 impossible("spo_cmp: trying to compare differing datatypes");
5645 switch (OV_typ(a)) {
5648 case SPOVAR_MAPCHAR:
5652 if (OV_i(b) > OV_i(a))
5653 val |= SP_CPUFLAG_LT;
5654 if (OV_i(b) < OV_i(a))
5655 val |= SP_CPUFLAG_GT;
5656 if (OV_i(b) == OV_i(a))
5657 val |= SP_CPUFLAG_EQ;
5658 c = opvar_new_int(val);
5661 c = opvar_new_int(!strcmp(OV_s(b), OV_s(a))
5666 c = opvar_new_int(0);
5669 splev_stack_push(coder->stack, c);
5675 spo_jmp(coder, lvl);
5683 spo_conditional_jump(coder, lvl);
5689 if (!OV_pop_i(tmpv))
5691 t = opvar_new_int((OV_i(tmpv) > 1) ? rn2(OV_i(tmpv)) : 0);
5692 splev_stack_push(coder->stack, t);
5697 struct opvar *a, *b, *t;
5699 if (!OV_pop_i(b) || !OV_pop_i(a))
5705 t = opvar_new_int(d(OV_i(a), OV_i(b)));
5706 splev_stack_push(coder->stack, t);
5715 spo_var_init(coder);
5717 case SPO_SHUFFLE_ARRAY:
5718 spo_shuffle_array(coder);
5720 case SPO_SEL_ADD: /* actually, logical or */
5722 struct opvar *sel1, *sel2, *pt;
5724 if (!OV_pop_typ(sel1, SPOVAR_SEL))
5725 panic("no sel1 for add");
5726 if (!OV_pop_typ(sel2, SPOVAR_SEL))
5727 panic("no sel2 for add");
5728 pt = selection_logical_oper(sel1, sel2, '|');
5731 splev_stack_push(coder->stack, pt);
5734 case SPO_SEL_COMPLEMENT: {
5735 struct opvar *sel, *pt;
5737 if (!OV_pop_typ(sel, SPOVAR_SEL))
5738 panic("no sel for not");
5739 pt = selection_not(sel);
5741 splev_stack_push(coder->stack, pt);
5744 case SPO_SEL_FILTER: /* sorta like logical and */
5746 struct opvar *filtertype;
5748 if (!OV_pop_i(filtertype))
5749 panic("no sel filter type");
5750 switch (OV_i(filtertype)) {
5751 case SPOFILTER_PERCENT: {
5752 struct opvar *tmp1, *sel;
5754 if (!OV_pop_i(tmp1))
5755 panic("no sel filter percent");
5756 if (!OV_pop_typ(sel, SPOVAR_SEL))
5757 panic("no sel filter");
5758 selection_filter_percent(sel, OV_i(tmp1));
5759 splev_stack_push(coder->stack, sel);
5763 case SPOFILTER_SELECTION: /* logical and */
5765 struct opvar *pt, *sel1, *sel2;
5767 if (!OV_pop_typ(sel1, SPOVAR_SEL))
5768 panic("no sel filter sel1");
5769 if (!OV_pop_typ(sel2, SPOVAR_SEL))
5770 panic("no sel filter sel2");
5771 pt = selection_logical_oper(sel1, sel2, '&');
5772 splev_stack_push(coder->stack, pt);
5777 case SPOFILTER_MAPCHAR: {
5778 struct opvar *pt, *tmp1, *sel;
5780 if (!OV_pop_typ(sel, SPOVAR_SEL))
5781 panic("no sel filter");
5782 if (!OV_pop_typ(tmp1, SPOVAR_MAPCHAR))
5783 panic("no sel filter mapchar");
5784 pt = selection_filter_mapchar(sel, tmp1);
5785 splev_stack_push(coder->stack, pt);
5791 panic("unknown sel filter type");
5793 opvar_free(filtertype);
5796 case SPO_SEL_POINT: {
5798 struct opvar *pt = selection_opvar((char *) 0);
5802 panic("no ter sel coord");
5803 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp));
5804 selection_setpoint(x, y, pt, 1);
5805 splev_stack_push(coder->stack, pt);
5810 case SPO_SEL_FILLRECT: {
5811 struct opvar *tmp, *pt = selection_opvar((char *) 0);
5812 schar x, y, x1, y1, x2, y2;
5815 panic("no ter sel region");
5816 x1 = min(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp)));
5817 y1 = min(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp)));
5818 x2 = max(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp)));
5819 y2 = max(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp)));
5820 get_location(&x1, &y1, ANY_LOC, coder->croom);
5821 get_location(&x2, &y2, ANY_LOC, coder->croom);
5822 x1 = (x1 < 0) ? 0 : x1;
5823 y1 = (y1 < 0) ? 0 : y1;
5824 x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
5825 y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
5826 if (coder->opcode == SPO_SEL_RECT) {
5827 for (x = x1; x <= x2; x++) {
5828 selection_setpoint(x, y1, pt, 1);
5829 selection_setpoint(x, y2, pt, 1);
5831 for (y = y1; y <= y2; y++) {
5832 selection_setpoint(x1, y, pt, 1);
5833 selection_setpoint(x2, y, pt, 1);
5836 for (x = x1; x <= x2; x++)
5837 for (y = y1; y <= y2; y++)
5838 selection_setpoint(x, y, pt, 1);
5840 splev_stack_push(coder->stack, pt);
5844 case SPO_SEL_LINE: {
5845 struct opvar *tmp = NULL, *tmp2 = NULL,
5846 *pt = selection_opvar((char *) 0);
5847 schar x1, y1, x2, y2;
5850 panic("no ter sel linecoord1");
5851 if (!OV_pop_c(tmp2))
5852 panic("no ter sel linecoord2");
5853 get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp));
5854 get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2));
5855 x1 = (x1 < 0) ? 0 : x1;
5856 y1 = (y1 < 0) ? 0 : y1;
5857 x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
5858 y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
5859 selection_do_line(x1, y1, x2, y2, pt);
5860 splev_stack_push(coder->stack, pt);
5865 case SPO_SEL_RNDLINE: {
5866 struct opvar *tmp = NULL, *tmp2 = NULL, *tmp3,
5867 *pt = selection_opvar((char *) 0);
5868 schar x1, y1, x2, y2;
5870 if (!OV_pop_i(tmp3))
5871 panic("no ter sel randline1");
5873 panic("no ter sel randline2");
5874 if (!OV_pop_c(tmp2))
5875 panic("no ter sel randline3");
5876 get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp));
5877 get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2));
5878 x1 = (x1 < 0) ? 0 : x1;
5879 y1 = (y1 < 0) ? 0 : y1;
5880 x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
5881 y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
5882 selection_do_randline(x1, y1, x2, y2, OV_i(tmp3), 12, pt);
5883 splev_stack_push(coder->stack, pt);
5889 case SPO_SEL_GROW: {
5890 struct opvar *dirs, *pt;
5892 if (!OV_pop_i(dirs))
5893 panic("no dirs for grow");
5894 if (!OV_pop_typ(pt, SPOVAR_SEL))
5895 panic("no selection for grow");
5896 selection_do_grow(pt, OV_i(dirs));
5897 splev_stack_push(coder->stack, pt);
5901 case SPO_SEL_FLOOD: {
5906 panic("no ter sel flood coord");
5907 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp));
5909 struct opvar *pt = selection_opvar((char *) 0);
5911 set_selection_floodfillchk(floodfillchk_match_under);
5912 floodfillchk_match_under_typ = levl[x][y].typ;
5913 selection_floodfill(pt, x, y, FALSE);
5914 splev_stack_push(coder->stack, pt);
5919 case SPO_SEL_RNDCOORD: {
5923 if (!OV_pop_typ(pt, SPOVAR_SEL))
5924 panic("no selection for rndcoord");
5925 if (selection_rndcoord(pt, &x, &y, FALSE)) {
5929 splev_stack_push(coder->stack, opvar_new_coord(x, y));
5933 case SPO_SEL_ELLIPSE: {
5934 struct opvar *filled, *xaxis, *yaxis, *pt;
5935 struct opvar *sel = selection_opvar((char *) 0);
5938 if (!OV_pop_i(filled))
5939 panic("no filled for ellipse");
5940 if (!OV_pop_i(yaxis))
5941 panic("no yaxis for ellipse");
5942 if (!OV_pop_i(xaxis))
5943 panic("no xaxis for ellipse");
5945 panic("no pt for ellipse");
5946 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(pt));
5947 selection_do_ellipse(sel, x, y, OV_i(xaxis), OV_i(yaxis),
5949 splev_stack_push(coder->stack, sel);
5956 case SPO_SEL_GRADIENT: {
5957 struct opvar *gtyp, *glim, *mind, *maxd, *gcoord, *coord2;
5961 if (!OV_pop_i(gtyp))
5962 panic("no gtyp for grad");
5963 if (!OV_pop_i(glim))
5964 panic("no glim for grad");
5965 if (!OV_pop_c(coord2))
5966 panic("no coord2 for grad");
5967 if (!OV_pop_c(gcoord))
5968 panic("no coord for grad");
5969 if (!OV_pop_i(maxd))
5970 panic("no maxd for grad");
5971 if (!OV_pop_i(mind))
5972 panic("no mind for grad");
5973 get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(gcoord));
5974 get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(coord2));
5976 sel = selection_opvar((char *) 0);
5977 selection_do_gradient(sel, x, y, x2, y2, OV_i(gtyp), OV_i(mind),
5978 OV_i(maxd), OV_i(glim));
5979 splev_stack_push(coder->stack, sel);
5990 panic("sp_level_coder: Unknown opcode %i", coder->opcode);
5994 coder->frame->n_opcode++;
5999 remove_boundary_syms();
6001 if (coder->check_inaccessibles)
6003 /* FIXME: Ideally, we want this call to only cover areas of the map
6004 * which were not inserted directly by the special level file (see
6005 * the insect legs on Baalzebub's level, for instance). Since that
6006 * is currently not possible, we overload the corrmaze flag for this
6009 if (!level.flags.corrmaze)
6010 wallification(1, 0, COLNO - 1, ROWNO - 1);
6014 if (coder->solidify)
6017 /* This must be done before sokoban_detect(),
6018 * otherwise branch stairs won't be premapped. */
6021 if (coder->premapped)
6025 struct sp_frame *tmpframe;
6027 tmpframe = coder->frame->next;
6028 frame_del(coder->frame);
6029 coder->frame = tmpframe;
6030 } while (coder->frame);
6046 boolean result = FALSE;
6047 struct version_info vers_info;
6049 fd = dlb_fopen(name, RDBMODE);
6052 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
6053 if (!check_version(&vers_info, name, TRUE)) {
6054 (void) dlb_fclose(fd);
6058 lvl = (sp_lev *) alloc(sizeof (sp_lev));
6059 result = sp_level_loader(fd, lvl);
6060 (void) dlb_fclose(fd);
6062 result = sp_level_coder(lvl);
6071 #pragma warning(pop)