1 /* NetHack 3.6 sp_lev.c $NHDT-Date: 1449269920 2015/12/04 22:58:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.77 $ */
2 /* Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed. See license for details. */
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
void FDECL(opvar_free_x
, (struct opvar
*));
40 STATIC_DCL
struct opvar
*FDECL(opvar_clone
, (struct opvar
*));
41 STATIC_DCL
struct opvar
*FDECL(opvar_var_conversion
, (struct sp_coder
*,
43 STATIC_DCL
struct splev_var
*FDECL(opvar_var_defined
, (struct sp_coder
*,
45 STATIC_DCL
struct opvar
*FDECL(splev_stack_getdat
, (struct sp_coder
*,
47 STATIC_DCL
struct opvar
*FDECL(splev_stack_getdat_any
, (struct sp_coder
*));
48 STATIC_DCL
void FDECL(variable_list_del
, (struct splev_var
*));
49 STATIC_DCL
void FDECL(lvlfill_maze_grid
, (int, int, int, int, SCHAR_P
));
50 STATIC_DCL
void FDECL(lvlfill_solid
, (SCHAR_P
, SCHAR_P
));
51 STATIC_DCL
void FDECL(set_wall_property
, (XCHAR_P
, XCHAR_P
, XCHAR_P
, XCHAR_P
,
53 STATIC_DCL
void NDECL(shuffle_alignments
);
54 STATIC_DCL
void NDECL(count_features
);
55 STATIC_DCL
void NDECL(remove_boundary_syms
);
56 STATIC_DCL
void FDECL(maybe_add_door
, (int, int, struct mkroom
*));
57 STATIC_DCL
void NDECL(link_doors_rooms
);
58 STATIC_DCL
void NDECL(fill_rooms
);
59 STATIC_DCL
int NDECL(rnddoor
);
60 STATIC_DCL
int NDECL(rndtrap
);
61 STATIC_DCL
void FDECL(get_location
, (schar
*, schar
*, int, struct mkroom
*));
62 STATIC_DCL boolean
FDECL(is_ok_location
, (SCHAR_P
, SCHAR_P
, int));
63 STATIC_DCL unpacked_coord
FDECL(get_unpacked_coord
, (long, int));
64 STATIC_DCL
void FDECL(get_location_coord
, (schar
*, schar
*, int,
65 struct mkroom
*, long));
66 STATIC_DCL
void FDECL(get_room_loc
, (schar
*, schar
*, struct mkroom
*));
67 STATIC_DCL
void FDECL(get_free_room_loc
, (schar
*, schar
*,
68 struct mkroom
*, packed_coord
));
69 STATIC_DCL boolean
FDECL(create_subroom
, (struct mkroom
*, XCHAR_P
, XCHAR_P
,
70 XCHAR_P
, XCHAR_P
, XCHAR_P
, XCHAR_P
));
71 STATIC_DCL
void FDECL(create_door
, (room_door
*, struct mkroom
*));
72 STATIC_DCL
void FDECL(create_trap
, (trap
*, struct mkroom
*));
73 STATIC_DCL
int FDECL(noncoalignment
, (ALIGNTYP_P
));
74 STATIC_DCL boolean
FDECL(m_bad_boulder_spot
, (int, int));
75 STATIC_DCL
void FDECL(create_monster
, (monster
*, struct mkroom
*));
76 STATIC_DCL
void FDECL(create_object
, (object
*, struct mkroom
*));
77 STATIC_DCL
void FDECL(create_altar
, (altar
*, struct mkroom
*));
78 STATIC_DCL
void FDECL(replace_terrain
, (replaceterrain
*, struct mkroom
*));
79 STATIC_DCL boolean
FDECL(search_door
, (struct mkroom
*,
80 xchar
*, xchar
*, XCHAR_P
, int));
81 STATIC_DCL
void NDECL(fix_stair_rooms
);
82 STATIC_DCL
void FDECL(create_corridor
, (corridor
*));
83 STATIC_DCL
struct mkroom
*FDECL(build_room
, (room
*, struct mkroom
*));
84 STATIC_DCL
void FDECL(light_region
, (region
*));
85 STATIC_DCL
void FDECL(wallify_map
, (int, int, int, int));
86 STATIC_DCL
void FDECL(maze1xy
, (coord
*, int));
87 STATIC_DCL
void NDECL(fill_empty_maze
);
88 STATIC_DCL boolean
FDECL(sp_level_loader
, (dlb
*, sp_lev
*));
89 STATIC_DCL boolean
FDECL(sp_level_free
, (sp_lev
*));
90 STATIC_DCL
void FDECL(splev_initlev
, (lev_init
*));
91 STATIC_DCL
struct sp_frame
*FDECL(frame_new
, (long));
92 STATIC_DCL
void FDECL(frame_del
, (struct sp_frame
*));
93 STATIC_DCL
void FDECL(spo_frame_push
, (struct sp_coder
*));
94 STATIC_DCL
void FDECL(spo_frame_pop
, (struct sp_coder
*));
95 STATIC_DCL
long FDECL(sp_code_jmpaddr
, (long, long));
96 STATIC_DCL
void FDECL(spo_call
, (struct sp_coder
*));
97 STATIC_DCL
void FDECL(spo_return
, (struct sp_coder
*));
98 STATIC_DCL
void FDECL(spo_end_moninvent
, (struct sp_coder
*));
99 STATIC_DCL
void FDECL(spo_pop_container
, (struct sp_coder
*));
100 STATIC_DCL
void FDECL(spo_message
, (struct sp_coder
*));
101 STATIC_DCL
void FDECL(spo_monster
, (struct sp_coder
*));
102 STATIC_DCL
void FDECL(spo_object
, (struct sp_coder
*));
103 STATIC_DCL
void FDECL(spo_level_flags
, (struct sp_coder
*));
104 STATIC_DCL
void FDECL(spo_initlevel
, (struct sp_coder
*));
105 STATIC_DCL
void FDECL(spo_engraving
, (struct sp_coder
*));
106 STATIC_DCL
void FDECL(spo_mineralize
, (struct sp_coder
*));
107 STATIC_DCL
void FDECL(spo_room
, (struct sp_coder
*));
108 STATIC_DCL
void FDECL(spo_endroom
, (struct sp_coder
*));
109 STATIC_DCL
void FDECL(spo_stair
, (struct sp_coder
*));
110 STATIC_DCL
void FDECL(spo_ladder
, (struct sp_coder
*));
111 STATIC_DCL
void FDECL(spo_grave
, (struct sp_coder
*));
112 STATIC_DCL
void FDECL(spo_altar
, (struct sp_coder
*));
113 STATIC_DCL
void FDECL(spo_trap
, (struct sp_coder
*));
114 STATIC_DCL
void FDECL(spo_gold
, (struct sp_coder
*));
115 STATIC_DCL
void FDECL(spo_corridor
, (struct sp_coder
*));
116 STATIC_DCL
struct opvar
*FDECL(selection_opvar
, (char *));
117 STATIC_DCL xchar
FDECL(selection_getpoint
, (int, int, struct opvar
*));
118 STATIC_DCL
void FDECL(selection_setpoint
, (int, int, struct opvar
*, XCHAR_P
));
119 STATIC_DCL
struct opvar
*FDECL(selection_not
, (struct opvar
*));
120 STATIC_DCL
struct opvar
*FDECL(selection_logical_oper
, (struct opvar
*,
121 struct opvar
*, CHAR_P
));
122 STATIC_DCL
struct opvar
*FDECL(selection_filter_mapchar
, (struct opvar
*,
124 STATIC_DCL
void FDECL(selection_filter_percent
, (struct opvar
*, int));
125 STATIC_DCL
int FDECL(selection_rndcoord
, (struct opvar
*, schar
*, schar
*,
127 STATIC_DCL
void FDECL(selection_do_grow
, (struct opvar
*, int));
128 STATIC_DCL
void FDECL(set_selection_floodfillchk
, (int FDECL((*), (int,int))));
129 STATIC_DCL
int FDECL(floodfillchk_match_under
, (int, int));
130 STATIC_DCL
int FDECL(floodfillchk_match_accessible
, (int, int));
131 STATIC_DCL
void FDECL(selection_floodfill
, (struct opvar
*, int, int,
133 STATIC_DCL
void FDECL(selection_do_ellipse
, (struct opvar
*, int, int,
135 STATIC_DCL
long FDECL(line_dist_coord
, (long, long, long, long, long, long));
136 STATIC_DCL
void FDECL(selection_do_gradient
, (struct opvar
*, long, long, long,
137 long, long, long, long, long));
138 STATIC_DCL
void FDECL(selection_do_line
, (SCHAR_P
, SCHAR_P
, SCHAR_P
, SCHAR_P
,
140 STATIC_DCL
void FDECL(selection_do_randline
, (SCHAR_P
, SCHAR_P
, SCHAR_P
,
141 SCHAR_P
, SCHAR_P
, SCHAR_P
,
143 STATIC_DCL
void FDECL(selection_iterate
, (struct opvar
*, select_iter_func
,
145 STATIC_DCL
void FDECL(sel_set_ter
, (int, int, genericptr_t
));
146 STATIC_DCL
void FDECL(sel_set_feature
, (int, int, genericptr_t
));
147 STATIC_DCL
void FDECL(sel_set_door
, (int, int, genericptr_t
));
148 STATIC_DCL
void FDECL(spo_door
, (struct sp_coder
*));
149 STATIC_DCL
void FDECL(spo_feature
, (struct sp_coder
*));
150 STATIC_DCL
void FDECL(spo_terrain
, (struct sp_coder
*));
151 STATIC_DCL
void FDECL(spo_replace_terrain
, (struct sp_coder
*));
152 STATIC_DCL boolean
FDECL(generate_way_out_method
, (int, int, struct opvar
*));
153 STATIC_DCL
void NDECL(ensure_way_out
);
154 STATIC_DCL
void FDECL(spo_levregion
, (struct sp_coder
*));
155 STATIC_DCL
void FDECL(spo_region
, (struct sp_coder
*));
156 STATIC_DCL
void FDECL(spo_drawbridge
, (struct sp_coder
*));
157 STATIC_DCL
void FDECL(spo_mazewalk
, (struct sp_coder
*));
158 STATIC_DCL
void FDECL(spo_wall_property
, (struct sp_coder
*));
159 STATIC_DCL
void FDECL(spo_room_door
, (struct sp_coder
*));
160 STATIC_DCL
void FDECL(sel_set_wallify
, (int, int, genericptr_t
));
161 STATIC_DCL
void FDECL(spo_wallify
, (struct sp_coder
*));
162 STATIC_DCL
void FDECL(spo_map
, (struct sp_coder
*));
163 STATIC_DCL
void FDECL(spo_jmp
, (struct sp_coder
*, sp_lev
*));
164 STATIC_DCL
void FDECL(spo_conditional_jump
, (struct sp_coder
*, sp_lev
*));
165 STATIC_DCL
void FDECL(spo_var_init
, (struct sp_coder
*));
167 STATIC_DCL
long FDECL(opvar_array_length
, (struct sp_coder
*));
169 STATIC_DCL
void FDECL(spo_shuffle_array
, (struct sp_coder
*));
170 STATIC_DCL boolean
FDECL(sp_level_coder
, (sp_lev
*));
181 #define sq(x) ((x) * (x))
186 #define Fread (void) dlb_fread
187 #define Fgetc (schar) dlb_fgetc
188 #define New(type) (type *) alloc(sizeof(type))
189 #define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned) size)
190 #define Free(ptr) if (ptr) free((genericptr_t) (ptr))
192 extern struct engr
*head_engr
;
194 extern int min_rx
, max_rx
, min_ry
, max_ry
; /* from mkmap.c */
196 /* positions touched by level elements explicitly defined in the des-file */
197 static char SpLev_Map
[COLNO
][ROWNO
];
199 static aligntyp ralign
[3] = { AM_CHAOTIC
, AM_NEUTRAL
, AM_LAWFUL
};
200 static NEARDATA xchar xstart
, ystart
;
201 static NEARDATA
char xsize
, ysize
;
203 char *lev_message
= 0;
204 lev_region
*lregions
= 0;
205 int num_lregions
= 0;
206 boolean splev_init_present
= FALSE
;
207 boolean icedpools
= FALSE
;
209 struct obj
*container_obj
[MAX_CONTAINMENT
];
210 int container_idx
= 0;
212 struct monst
*invent_carrying_monster
= NULL
;
214 #define SPLEV_STACK_RESERVE 128
221 for (x
= 0; x
< COLNO
; x
++)
222 for (y
= 0; y
< ROWNO
; y
++)
223 if (IS_STWALL(levl
[x
][y
].typ
) && !SpLev_Map
[x
][y
])
224 levl
[x
][y
].wall_info
|= (W_NONDIGGABLE
| W_NONPASSWALL
);
229 struct splevstack
*st
;
233 st
->depth_alloc
= SPLEV_STACK_RESERVE
;
235 (struct opvar
**) alloc(st
->depth_alloc
* sizeof(struct opvar
*));
241 struct splevstack
*st
;
246 if (st
->stackdata
&& st
->depth
) {
247 for (i
= 0; i
< st
->depth
; i
++) {
248 switch (st
->stackdata
[i
]->spovartyp
) {
258 case SPOVAR_VARIABLE
:
261 Free(st
->stackdata
[i
]->vardata
.str
);
262 st
->stackdata
[i
]->vardata
.str
= NULL
;
265 Free(st
->stackdata
[i
]);
266 st
->stackdata
[i
] = NULL
;
270 st
->stackdata
= NULL
;
271 st
->depth
= st
->depth_alloc
= 0;
277 splev_stack_push(st
, v
)
278 struct splevstack
*st
;
284 panic("splev_stack_push: no stackdata allocated?");
286 if (st
->depth
>= st
->depth_alloc
) {
287 struct opvar
**tmp
= (struct opvar
**) alloc(
288 (st
->depth_alloc
+ SPLEV_STACK_RESERVE
) * sizeof(struct opvar
*));
290 (void) memcpy(tmp
, st
->stackdata
,
291 st
->depth_alloc
* sizeof(struct opvar
*));
294 st
->depth_alloc
+= SPLEV_STACK_RESERVE
;
297 st
->stackdata
[st
->depth
] = v
;
303 struct splevstack
*st
;
305 struct opvar
*ret
= NULL
;
310 panic("splev_stack_pop: no stackdata allocated?");
314 ret
= st
->stackdata
[st
->depth
];
315 st
->stackdata
[st
->depth
] = NULL
;
318 impossible("splev_stack_pop: empty stack?");
323 splev_stack_reverse(st
)
324 struct splevstack
*st
;
332 panic("splev_stack_reverse: no stackdata allocated?");
333 for (i
= 0; i
< (st
->depth
/ 2); i
++) {
334 tmp
= st
->stackdata
[i
];
335 st
->stackdata
[i
] = st
->stackdata
[st
->depth
- i
- 1];
336 st
->stackdata
[st
->depth
- i
- 1] = tmp
;
341 #define OV_typ(o) (o->spovartyp)
342 #define OV_i(o) (o->vardata.l)
343 #define OV_s(o) (o->vardata.str)
345 #define OV_pop_i(x) (x = splev_stack_getdat(coder, SPOVAR_INT))
346 #define OV_pop_c(x) (x = splev_stack_getdat(coder, SPOVAR_COORD))
347 #define OV_pop_r(x) (x = splev_stack_getdat(coder, SPOVAR_REGION))
348 #define OV_pop_s(x) (x = splev_stack_getdat(coder, SPOVAR_STRING))
349 #define OV_pop(x) (x = splev_stack_getdat_any(coder))
350 #define OV_pop_typ(x, typ) (x = splev_stack_getdat(coder, typ))
356 struct opvar
*tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
358 tmpov
->spovartyp
= SPOVAR_STRING
;
361 tmpov
->vardata
.str
= (char *) alloc(len
+ 1);
362 (void) memcpy((genericptr_t
) tmpov
->vardata
.str
, (genericptr_t
) s
,
364 tmpov
->vardata
.str
[len
] = '\0';
366 tmpov
->vardata
.str
= NULL
;
374 struct opvar
*tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
376 tmpov
->spovartyp
= SPOVAR_INT
;
377 tmpov
->vardata
.l
= i
;
382 opvar_new_coord(x
, y
)
385 struct opvar
*tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
387 tmpov
->spovartyp
= SPOVAR_COORD
;
388 tmpov
->vardata
.l
= SP_COORD_PACK(x
, y
);
394 opvar_new_region(x1
,y1
,x2
,y2
)
397 struct opvar
*tmpov
= (struct opvar
*)alloc(sizeof (struct opvar
));
399 tmpov
->spovartyp
= SPOVAR_REGION
;
400 tmpov
->vardata
.l
= SP_REGION_PACK(x1
,y1
,x2
,y2
);
411 switch (ov
->spovartyp
) {
419 case SPOVAR_VARIABLE
:
422 Free(ov
->vardata
.str
);
425 impossible("Unknown opvar value type (%i)!", ov
->spovartyp
);
431 * Name of current function for use in messages:
432 * __func__ -- C99 standard;
433 * __FUNCTION__ -- gcc extension, starting before C99 and continuing after;
434 * picked up by other compilers (or vice versa?);
435 * __FUNC__ -- supported by Borland;
436 * nhFunc -- slightly intrusive but fully portable nethack construct
437 * for any version of any compiler.
439 #define opvar_free(ov) \
445 impossible("opvar_free(), %s", nhFunc); \
455 panic("no opvar to clone");
456 tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
457 tmpov
->spovartyp
= ov
->spovartyp
;
458 switch (ov
->spovartyp
) {
465 tmpov
->vardata
.l
= ov
->vardata
.l
;
467 case SPOVAR_VARIABLE
:
470 tmpov
->vardata
.str
= dupstr(ov
->vardata
.str
);
473 impossible("Unknown push value type (%i)!", ov
->spovartyp
);
479 opvar_var_conversion(coder
, ov
)
480 struct sp_coder
*coder
;
483 static const char nhFunc
[] = "opvar_var_conversion";
484 struct splev_var
*tmp
;
486 struct opvar
*array_idx
= NULL
;
490 if (ov
->spovartyp
!= SPOVAR_VARIABLE
)
492 tmp
= coder
->frame
->variables
;
494 if (!strcmp(tmp
->name
, OV_s(ov
))) {
495 if ((tmp
->svtyp
& SPOVAR_ARRAY
)) {
496 array_idx
= opvar_var_conversion(coder
,
497 splev_stack_pop(coder
->stack
));
498 if (!array_idx
|| OV_typ(array_idx
) != SPOVAR_INT
)
499 panic("array idx not an int");
500 if (tmp
->array_len
< 1)
501 panic("array len < 1");
502 OV_i(array_idx
) = (OV_i(array_idx
) % tmp
->array_len
);
503 tmpov
= opvar_clone(tmp
->data
.arrayvalues
[OV_i(array_idx
)]);
504 opvar_free(array_idx
);
507 tmpov
= opvar_clone(tmp
->data
.value
);
517 opvar_var_defined(coder
, name
)
518 struct sp_coder
*coder
;
521 struct splev_var
*tmp
;
525 tmp
= coder
->frame
->variables
;
527 if (!strcmp(tmp
->name
, name
))
535 splev_stack_getdat(coder
, typ
)
536 struct sp_coder
*coder
;
539 static const char nhFunc
[] = "splev_stack_getdat";
540 if (coder
&& coder
->stack
) {
541 struct opvar
*tmp
= splev_stack_pop(coder
->stack
);
542 struct opvar
*ret
= NULL
;
545 panic("no value type %i in stack.", typ
);
546 if (tmp
->spovartyp
== SPOVAR_VARIABLE
) {
547 ret
= opvar_var_conversion(coder
, tmp
);
551 if (tmp
->spovartyp
== typ
)
553 else opvar_free(tmp
);
559 splev_stack_getdat_any(coder
)
560 struct sp_coder
*coder
;
562 static const char nhFunc
[] = "splev_stack_getdat_any";
563 if (coder
&& coder
->stack
) {
564 struct opvar
*tmp
= splev_stack_pop(coder
->stack
);
565 if (tmp
&& tmp
->spovartyp
== SPOVAR_VARIABLE
) {
566 struct opvar
*ret
= opvar_var_conversion(coder
, tmp
);
576 variable_list_del(varlist
)
577 struct splev_var
*varlist
;
579 static const char nhFunc
[] = "variable_list_del";
580 struct splev_var
*tmp
= varlist
;
586 if ((tmp
->svtyp
& SPOVAR_ARRAY
)) {
587 long idx
= tmp
->array_len
;
590 opvar_free(tmp
->data
.arrayvalues
[idx
]);
592 Free(tmp
->data
.arrayvalues
);
594 opvar_free(tmp
->data
.value
);
603 lvlfill_maze_grid(x1
, y1
, x2
, y2
, filling
)
609 for (x
= x1
; x
<= x2
; x
++)
610 for (y
= y1
; y
<= y2
; y
++) {
611 if (level
.flags
.corrmaze
)
612 levl
[x
][y
].typ
= STONE
;
615 (y
< 2 || ((x
% 2) && (y
% 2))) ? STONE
: filling
;
620 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
;
641 for (y
= max(y1
, 0); y
<= min(y2
, ROWNO
- 1); y
++)
642 for (x
= max(x1
, 0); x
<= min(x2
, COLNO
- 1); x
++)
643 if (IS_STWALL(levl
[x
][y
].typ
) || IS_TREE(levl
[x
][y
].typ
))
644 levl
[x
][y
].wall_info
|= prop
;
653 /* shuffle 3 alignments */
656 ralign
[2] = ralign
[i
];
660 ralign
[1] = ralign
[0];
666 * Count the different features (sinks, fountains) in the level.
673 level
.flags
.nfountains
= level
.flags
.nsinks
= 0;
674 for (y
= 0; y
< ROWNO
; y
++)
675 for (x
= 0; x
< COLNO
; x
++) {
676 int typ
= levl
[x
][y
].typ
;
678 level
.flags
.nfountains
++;
679 else if (typ
== SINK
)
680 level
.flags
.nsinks
++;
685 remove_boundary_syms()
688 * If any CROSSWALLs are found, must change to ROOM after REGION's
689 * are laid out. CROSSWALLS are used to specify "invisible"
690 * boundaries where DOOR syms look bad or aren't desirable.
693 boolean has_bounds
= FALSE
;
695 for (x
= 0; x
< COLNO
- 1; x
++)
696 for (y
= 0; y
< ROWNO
- 1; y
++)
697 if (levl
[x
][y
].typ
== CROSSWALL
) {
702 for (x
= 0; x
< x_maze_max
; x
++)
703 for (y
= 0; y
< y_maze_max
; y
++)
704 if ((levl
[x
][y
].typ
== CROSSWALL
) && SpLev_Map
[x
][y
])
705 levl
[x
][y
].typ
= ROOM
;
710 maybe_add_door(x
, y
, droom
)
712 struct mkroom
*droom
;
714 if (droom
->hx
>= 0 && doorindex
< DOORMAX
&& inside_room(droom
, x
, y
))
715 add_door(x
, y
, droom
);
724 for (y
= 0; y
< ROWNO
; y
++)
725 for (x
= 0; x
< COLNO
; x
++)
726 if (IS_DOOR(levl
[x
][y
].typ
) || levl
[x
][y
].typ
== SDOOR
) {
727 for (tmpi
= 0; tmpi
< nroom
; tmpi
++) {
728 maybe_add_door(x
, y
, &rooms
[tmpi
]);
729 for (m
= 0; m
< rooms
[tmpi
].nsubrooms
; m
++) {
730 maybe_add_door(x
, y
, rooms
[tmpi
].sbrooms
[m
]);
741 for (tmpi
= 0; tmpi
< nroom
; tmpi
++) {
743 if (rooms
[tmpi
].needfill
)
744 fill_room(&rooms
[tmpi
], (rooms
[tmpi
].needfill
== 2));
745 for (m
= 0; m
< rooms
[tmpi
].nsubrooms
; m
++)
746 if (rooms
[tmpi
].sbrooms
[m
]->needfill
)
747 fill_room(rooms
[tmpi
].sbrooms
[m
], FALSE
);
752 * Choose randomly the state (nodoor, open, closed or locked) for a door
764 * Select a random trap
772 rtrap
= rnd(TRAPNUM
- 1);
774 case HOLE
: /* no random holes on special levels */
775 case VIBRATING_SQUARE
:
780 if (!Can_dig_down(&u
.uz
))
785 if (level
.flags
.noteleport
)
788 case ROLLING_BOULDER_TRAP
:
790 if (In_endgame(&u
.uz
))
794 } while (rtrap
== NO_TRAP
);
799 * Coordinates in special level files are handled specially:
801 * if x or y is < 0, we generate a random coordinate.
802 * The "humidity" flag is used to insure that engravings aren't
803 * created underwater, or eels on dry land.
806 get_location(x
, y
, humidity
, croom
)
809 struct mkroom
*croom
;
817 sx
= croom
->hx
- mx
+ 1;
818 sy
= croom
->hy
- my
+ 1;
826 if (*x
>= 0) { /* normal locations */
829 } else { /* random location */
831 if (croom
) { /* handle irregular areas */
833 somexy(croom
, &tmpc
);
837 *x
= mx
+ rn2((int) sx
);
838 *y
= my
+ rn2((int) sy
);
840 if (is_ok_location(*x
, *y
, humidity
))
842 } while (++cpt
< 100);
847 for (xx
= 0; xx
< sx
; xx
++)
848 for (yy
= 0; yy
< sy
; yy
++) {
851 if (is_ok_location(*x
, *y
, humidity
))
854 if (!(humidity
& NO_LOC_WARN
)) {
855 impossible("get_location: can't find a place!");
864 if (!(humidity
& ANY_LOC
) && !isok(*x
, *y
)) {
865 if (!(humidity
& NO_LOC_WARN
)) {
866 /*warning("get_location: (%d,%d) out of bounds", *x, *y);*/
876 is_ok_location(x
, y
, humidity
)
878 register int humidity
;
882 if (Is_waterlevel(&u
.uz
))
883 return TRUE
; /* accept any spot */
885 /* TODO: Should perhaps check if wall is diggable/passwall? */
886 if (humidity
& ANY_LOC
)
889 if ((humidity
& SOLID
) && IS_ROCK(levl
[x
][y
].typ
))
892 if (humidity
& DRY
) {
893 typ
= levl
[x
][y
].typ
;
894 if (typ
== ROOM
|| typ
== AIR
|| typ
== CLOUD
|| typ
== ICE
898 if ((humidity
& WET
) && is_pool(x
, y
))
900 if ((humidity
& HOT
) && is_lava(x
, y
))
906 get_unpacked_coord(loc
, defhumidity
)
910 static unpacked_coord c
;
912 if (loc
& SP_COORD_IS_RANDOM
) {
915 c
.getloc_flags
= (loc
& ~SP_COORD_IS_RANDOM
);
917 c
.getloc_flags
= defhumidity
;
920 c
.getloc_flags
= defhumidity
;
921 c
.x
= SP_COORD_X(loc
);
922 c
.y
= SP_COORD_Y(loc
);
928 get_location_coord(x
, y
, humidity
, croom
, crd
)
931 struct mkroom
*croom
;
936 c
= get_unpacked_coord(crd
, humidity
);
939 get_location(x
, y
, c
.getloc_flags
| (c
.is_random
? NO_LOC_WARN
: 0),
941 if (*x
== -1 && *y
== -1 && c
.is_random
)
942 get_location(x
, y
, humidity
, croom
);
946 * Get a relative position inside a room.
947 * negative values for x or y means RANDOM!
951 get_room_loc(x
, y
, croom
)
953 struct mkroom
*croom
;
957 if (*x
< 0 && *y
< 0) {
958 if (somexy(croom
, &c
)) {
962 panic("get_room_loc : can't find a place!");
965 *x
= rn2(croom
->hx
- croom
->lx
+ 1);
967 *y
= rn2(croom
->hy
- croom
->ly
+ 1);
974 * Get a relative position inside a room.
975 * negative values for x or y means RANDOM!
978 get_free_room_loc(x
, y
, croom
, pos
)
980 struct mkroom
*croom
;
984 register int trycnt
= 0;
986 get_location_coord(&try_x
, &try_y
, DRY
, croom
, pos
);
987 if (levl
[try_x
][try_y
].typ
!= ROOM
) {
989 try_x
= *x
, try_y
= *y
;
990 get_room_loc(&try_x
, &try_y
, croom
);
991 } while (levl
[try_x
][try_y
].typ
!= ROOM
&& ++trycnt
<= 100);
994 panic("get_free_room_loc: can't find a place!");
996 *x
= try_x
, *y
= try_y
;
1000 check_room(lowx
, ddx
, lowy
, ddy
, vault
)
1001 xchar
*lowx
, *ddx
, *lowy
, *ddy
;
1004 register int x
, y
, hix
= *lowx
+ *ddx
, hiy
= *lowy
+ *ddy
;
1005 register struct rm
*lev
;
1006 int xlim
, ylim
, ymax
;
1008 xlim
= XLIM
+ (vault
? 1 : 0);
1009 ylim
= YLIM
+ (vault
? 1 : 0);
1015 if (hix
> COLNO
- 3)
1017 if (hiy
> ROWNO
- 3)
1020 if (hix
<= *lowx
|| hiy
<= *lowy
)
1023 /* check area around room (and make room smaller if necessary) */
1024 for (x
= *lowx
- xlim
; x
<= hix
+ xlim
; x
++) {
1025 if (x
<= 0 || x
>= COLNO
)
1034 for (; y
<= ymax
; y
++) {
1037 debugpline2("strange area [%d,%d] in check_room.", x
, y
);
1042 *lowx
= x
+ xlim
+ 1;
1046 *lowy
= y
+ ylim
+ 1;
1059 * Create a new room.
1060 * This is still very incomplete...
1063 create_room(x
, y
, w
, h
, xal
, yal
, rtype
, rlit
)
1070 int wtmp
, htmp
, xaltmp
, yaltmp
, xtmp
, ytmp
;
1073 boolean vault
= FALSE
;
1074 int xlim
= XLIM
, ylim
= YLIM
;
1076 if (rtype
== -1) /* Is the type random ? */
1079 if (rtype
== VAULT
) {
1085 /* on low levels the room is lit (usually) */
1086 /* some other rooms may require lighting */
1088 /* is light state random ? */
1090 rlit
= (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? TRUE
: FALSE
;
1093 * Here we will try to create a room. If some parameters are
1094 * random we are willing to make several try before we give
1098 xchar xborder
, yborder
;
1106 /* First case : a totally random room */
1108 if ((xtmp
< 0 && ytmp
< 0 && wtmp
< 0 && xaltmp
< 0 && yaltmp
< 0)
1110 xchar hx
, hy
, lx
, ly
, dx
, dy
;
1111 r1
= rnd_rect(); /* Get a random rectangle */
1113 if (!r1
) { /* No more free rectangles ! */
1114 debugpline0("No more rects...");
1124 dx
= 2 + rn2((hx
- lx
> 28) ? 12 : 8);
1129 xborder
= (lx
> 0 && hx
< COLNO
- 1) ? 2 * xlim
: xlim
+ 1;
1130 yborder
= (ly
> 0 && hy
< ROWNO
- 1) ? 2 * ylim
: ylim
+ 1;
1131 if (hx
- lx
< dx
+ 3 + xborder
|| hy
- ly
< dy
+ 3 + yborder
) {
1135 xabs
= lx
+ (lx
> 0 ? xlim
: 3)
1136 + rn2(hx
- (lx
> 0 ? lx
: 3) - dx
- xborder
+ 1);
1137 yabs
= ly
+ (ly
> 0 ? ylim
: 2)
1138 + rn2(hy
- (ly
> 0 ? ly
: 2) - dy
- yborder
+ 1);
1139 if (ly
== 0 && hy
>= (ROWNO
- 1) && (!nroom
|| !rn2(nroom
))
1140 && (yabs
+ dy
> ROWNO
/ 2)) {
1142 if (nroom
< 4 && dy
> 1)
1145 if (!check_room(&xabs
, &dx
, &yabs
, &dy
, vault
)) {
1153 r2
.hx
= xabs
+ wtmp
;
1154 r2
.hy
= yabs
+ htmp
;
1155 } else { /* Only some parameters are random */
1157 if (xtmp
< 0 && ytmp
< 0) { /* Position is RANDOM */
1162 if (wtmp
< 0 || htmp
< 0) { /* Size is RANDOM */
1166 if (xaltmp
== -1) /* Horizontal alignment is RANDOM */
1168 if (yaltmp
== -1) /* Vertical alignment is RANDOM */
1171 /* Try to generate real (absolute) coordinates here! */
1173 xabs
= (((xtmp
- 1) * COLNO
) / 5) + 1;
1174 yabs
= (((ytmp
- 1) * ROWNO
) / 5) + 1;
1179 xabs
+= (COLNO
/ 5) - wtmp
;
1182 xabs
+= ((COLNO
/ 5) - wtmp
) / 2;
1189 yabs
+= (ROWNO
/ 5) - htmp
;
1192 yabs
+= ((ROWNO
/ 5) - htmp
) / 2;
1196 if (xabs
+ wtmp
- 1 > COLNO
- 2)
1197 xabs
= COLNO
- wtmp
- 3;
1200 if (yabs
+ htmp
- 1 > ROWNO
- 2)
1201 yabs
= ROWNO
- htmp
- 3;
1205 /* Try to find a rectangle that fit our room ! */
1209 r2
.hx
= xabs
+ wtmp
+ rndpos
;
1210 r2
.hy
= yabs
+ htmp
+ rndpos
;
1213 } while (++trycnt
<= 100 && !r1
);
1214 if (!r1
) { /* creation of room failed ? */
1217 split_rects(r1
, &r2
);
1220 smeq
[nroom
] = nroom
;
1221 add_room(xabs
, yabs
, xabs
+ wtmp
- 1, yabs
+ htmp
- 1, rlit
, rtype
,
1224 rooms
[nroom
].lx
= xabs
;
1225 rooms
[nroom
].ly
= yabs
;
1231 * Create a subroom in room proom at pos x,y with width w & height h.
1232 * x & y are relative to the parent room.
1235 create_subroom(proom
, x
, y
, w
, h
, rtype
, rlit
)
1236 struct mkroom
*proom
;
1241 xchar width
, height
;
1243 width
= proom
->hx
- proom
->lx
+ 1;
1244 height
= proom
->hy
- proom
->ly
+ 1;
1246 /* There is a minimum size for the parent room */
1247 if (width
< 4 || height
< 4)
1250 /* Check for random position, size, etc... */
1255 h
= rnd(height
- 3);
1257 x
= rnd(width
- w
- 1) - 1;
1259 y
= rnd(height
- h
- 1) - 1;
1264 if ((x
+ w
+ 1) == width
)
1266 if ((y
+ h
+ 1) == height
)
1271 rlit
= (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? TRUE
: FALSE
;
1272 add_subroom(proom
, proom
->lx
+ x
, proom
->ly
+ y
, proom
->lx
+ x
+ w
- 1,
1273 proom
->ly
+ y
+ h
- 1, rlit
, rtype
, FALSE
);
1278 * Create a new door in a room.
1279 * It's placed on a wall (north, south, east or west).
1282 create_door(dd
, broom
)
1284 struct mkroom
*broom
;
1287 int trycnt
= 0, wtry
= 0;
1289 if (dd
->secret
== -1)
1290 dd
->secret
= rn2(2);
1292 if (dd
->mask
== -1) {
1293 /* is it a locked door, closed, or a doorway? */
1297 dd
->mask
= D_ISOPEN
;
1299 dd
->mask
= D_LOCKED
;
1301 dd
->mask
= D_CLOSED
;
1302 if (dd
->mask
!= D_ISOPEN
&& !rn2(25))
1303 dd
->mask
|= D_TRAPPED
;
1305 dd
->mask
= D_NODOOR
;
1308 dd
->mask
= D_LOCKED
;
1310 dd
->mask
= D_CLOSED
;
1313 dd
->mask
|= D_TRAPPED
;
1318 register int dwall
, dpos
;
1321 if (dwall
== -1) /* The wall is RANDOM */
1322 dwall
= 1 << rn2(4);
1326 /* Convert wall and pos into an absolute coordinate! */
1330 if (!(dwall
& W_NORTH
))
1334 + ((dpos
== -1) ? rn2(1 + (broom
->hx
- broom
->lx
)) : dpos
);
1335 if (IS_ROCK(levl
[x
][y
- 1].typ
))
1339 if (!(dwall
& W_SOUTH
))
1343 + ((dpos
== -1) ? rn2(1 + (broom
->hx
- broom
->lx
)) : dpos
);
1344 if (IS_ROCK(levl
[x
][y
+ 1].typ
))
1348 if (!(dwall
& W_WEST
))
1352 + ((dpos
== -1) ? rn2(1 + (broom
->hy
- broom
->ly
)) : dpos
);
1353 if (IS_ROCK(levl
[x
- 1][y
].typ
))
1357 if (!(dwall
& W_EAST
))
1361 + ((dpos
== -1) ? rn2(1 + (broom
->hy
- broom
->ly
)) : dpos
);
1362 if (IS_ROCK(levl
[x
+ 1][y
].typ
))
1367 panic("create_door: No wall for door!");
1375 } while (++trycnt
<= 100);
1377 impossible("create_door: Can't find a proper place!");
1380 levl
[x
][y
].typ
= (dd
->secret
? SDOOR
: DOOR
);
1381 levl
[x
][y
].doormask
= dd
->mask
;
1385 * Create a secret door in croom on any one of the specified walls.
1388 create_secret_door(croom
, walls
)
1389 struct mkroom
*croom
;
1390 xchar walls
; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
1392 xchar sx
, sy
; /* location of the secret door */
1395 for (count
= 0; count
< 100; count
++) {
1396 sx
= rn1(croom
->hx
- croom
->lx
+ 1, croom
->lx
);
1397 sy
= rn1(croom
->hy
- croom
->ly
+ 1, croom
->ly
);
1401 if (!(walls
& W_NORTH
))
1405 case 1: /* bottom */
1406 if (!(walls
& W_SOUTH
))
1411 if (!(walls
& W_EAST
))
1416 if (!(walls
& W_WEST
))
1422 if (okdoor(sx
, sy
)) {
1423 levl
[sx
][sy
].typ
= SDOOR
;
1424 levl
[sx
][sy
].doormask
= D_CLOSED
;
1429 impossible("couldn't create secret door on any walls 0x%x", walls
);
1433 * Create a trap in a room.
1436 create_trap(t
, croom
)
1438 struct mkroom
*croom
;
1444 get_free_room_loc(&x
, &y
, croom
, t
->coord
);
1448 get_location_coord(&x
, &y
, DRY
, croom
, t
->coord
);
1449 } while ((levl
[x
][y
].typ
== STAIRS
|| levl
[x
][y
].typ
== LADDER
)
1450 && ++trycnt
<= 100);
1458 mktrap(t
->type
, 1, (struct mkroom
*) 0, &tm
);
1462 * Create a monster in a room.
1465 noncoalignment(alignment
)
1472 return (k
? -1 : 1);
1473 return (k
? -alignment
: 0);
1476 /* attempt to screen out locations where a mimic-as-boulder shouldn't occur */
1478 m_bad_boulder_spot(x
, y
)
1483 /* avoid trap locations */
1486 /* try to avoid locations which already have a boulder (this won't
1487 actually work; we get called before objects have been placed...) */
1488 if (sobj_at(BOULDER
, x
, y
))
1490 /* avoid closed doors */
1492 if (IS_DOOR(lev
->typ
) && (lev
->doormask
& (D_CLOSED
| D_LOCKED
)) != 0)
1499 create_monster(m
, croom
)
1501 struct mkroom
*croom
;
1508 struct permonst
*pm
;
1512 class = (char) def_char_to_monclass((char) m
->class);
1516 if (class == MAXMCLASSES
)
1517 panic("create_monster: unknown monster class '%c'", m
->class);
1519 amask
= (m
->align
== AM_SPLEV_CO
)
1520 ? Align2amask(u
.ualignbase
[A_ORIGINAL
])
1521 : (m
->align
== AM_SPLEV_NONCO
)
1522 ? Align2amask(noncoalignment(u
.ualignbase
[A_ORIGINAL
]))
1523 : (m
->align
<= -(MAX_REGISTERS
+ 1))
1525 : (m
->align
< 0 ? ralign
[-m
->align
- 1] : m
->align
);
1528 pm
= (struct permonst
*) 0;
1529 else if (m
->id
!= NON_PM
) {
1531 g_mvflags
= (unsigned) mvitals
[monsndx(pm
)].mvflags
;
1532 if ((pm
->geno
& G_UNIQ
) && (g_mvflags
& G_EXTINCT
))
1534 else if (g_mvflags
& G_GONE
) /* genocided or extinct */
1535 pm
= (struct permonst
*) 0; /* make random monster */
1537 pm
= mkclass(class, G_NOGEN
);
1538 /* if we can't get a specific monster type (pm == 0) then the
1539 class has been genocided, so settle for a random monster */
1541 if (In_mines(&u
.uz
) && pm
&& your_race(pm
)
1542 && (Race_if(PM_DWARF
) || Race_if(PM_GNOME
)) && rn2(3))
1543 pm
= (struct permonst
*) 0;
1547 if (pm
->mlet
== S_EEL
|| amphibious(pm
) || is_swimmer(pm
))
1549 if (is_flyer(pm
) || is_floater(pm
))
1551 if (passes_walls(pm
) || noncorporeal(pm
))
1555 /* If water-liking monster, first try is without DRY */
1556 get_location_coord(&x
, &y
, loc
| NO_LOC_WARN
, croom
, m
->coord
);
1557 if (x
== -1 && y
== -1) {
1559 get_location_coord(&x
, &y
, loc
, croom
, m
->coord
);
1562 get_location_coord(&x
, &y
, DRY
, croom
, m
->coord
);
1565 /* try to find a close place if someone else is already there */
1566 if (MON_AT(x
, y
) && enexto(&cc
, x
, y
, pm
))
1569 if (m
->align
!= -(MAX_REGISTERS
+ 2))
1570 mtmp
= mk_roamer(pm
, Amask2align(amask
), x
, y
, m
->peaceful
);
1571 else if (PM_ARCHEOLOGIST
<= m
->id
&& m
->id
<= PM_WIZARD
)
1572 mtmp
= mk_mplayer(pm
, x
, y
, FALSE
);
1574 mtmp
= makemon(pm
, x
, y
, NO_MM_FLAGS
);
1577 x
= mtmp
->mx
, y
= mtmp
->my
; /* sanity precaution */
1579 /* handle specific attributes for some special monsters */
1581 mtmp
= christen_monst(mtmp
, m
->name
.str
);
1584 * This is currently hardwired for mimics only. It should
1585 * eventually be expanded.
1587 if (m
->appear_as
.str
1588 && ((mtmp
->data
->mlet
== S_MIMIC
) || mtmp
->cham
)
1589 && !Protection_from_shape_changers
) {
1592 switch (m
->appear
) {
1595 "create_monster: mon has an appearance, \"%s\", but no type",
1599 case M_AP_FURNITURE
:
1600 for (i
= 0; i
< MAXPCHARS
; i
++)
1601 if (!strcmp(defsyms
[i
].explanation
, m
->appear_as
.str
))
1603 if (i
== MAXPCHARS
) {
1604 impossible("create_monster: can't find feature \"%s\"",
1607 mtmp
->m_ap_type
= M_AP_FURNITURE
;
1608 mtmp
->mappearance
= i
;
1613 for (i
= 0; i
< NUM_OBJECTS
; i
++)
1614 if (OBJ_NAME(objects
[i
])
1615 && !strcmp(OBJ_NAME(objects
[i
]), m
->appear_as
.str
))
1617 if (i
== NUM_OBJECTS
) {
1618 impossible("create_monster: can't find object \"%s\"",
1621 mtmp
->m_ap_type
= M_AP_OBJECT
;
1622 mtmp
->mappearance
= i
;
1623 /* try to avoid placing mimic boulder on a trap */
1624 if (i
== BOULDER
&& m
->x
< 0
1625 && m_bad_boulder_spot(x
, y
)) {
1626 int retrylimit
= 10;
1628 remove_monster(x
, y
);
1632 get_location(&x
, &y
, DRY
, croom
);
1633 if (MON_AT(x
, y
) && enexto(&cc
, x
, y
, pm
))
1635 } while (m_bad_boulder_spot(x
, y
)
1636 && --retrylimit
> 0);
1637 place_monster(mtmp
, x
, y
);
1638 /* if we didn't find a good spot
1639 then mimic something else */
1641 set_mimic_sym(mtmp
);
1646 case M_AP_MONSTER
: {
1649 if (!strcmpi(m
->appear_as
.str
, "random"))
1650 mndx
= select_newcham_form(mtmp
);
1652 mndx
= name_to_mon(m
->appear_as
.str
);
1653 if ((mndx
!= NON_PM
) && (&mons
[mndx
] != mtmp
->data
)) {
1654 struct permonst
*mdat
= &mons
[mndx
];
1655 struct permonst
*olddata
= mtmp
->data
;
1657 mgender_from_permonst(mtmp
, mdat
);
1658 set_mon_data(mtmp
, mdat
, 0);
1659 if (emits_light(olddata
) != emits_light(mtmp
->data
)) {
1660 /* used to give light, now doesn't, or vice versa,
1661 or light's range has changed */
1662 if (emits_light(olddata
))
1663 del_light_source(LS_MONSTER
, (genericptr_t
) mtmp
);
1664 if (emits_light(mtmp
->data
))
1665 new_light_source(mtmp
->mx
, mtmp
->my
,
1666 emits_light(mtmp
->data
),
1667 LS_MONSTER
, (genericptr_t
) mtmp
);
1669 if (!mtmp
->perminvis
|| pm_invisible(olddata
))
1670 mtmp
->perminvis
= pm_invisible(mdat
);
1676 "create_monster: unimplemented mon appear type [%d,\"%s\"]",
1677 m
->appear
, m
->appear_as
.str
);
1680 if (does_block(x
, y
, &levl
[x
][y
]))
1684 if (m
->peaceful
>= 0) {
1685 mtmp
->mpeaceful
= m
->peaceful
;
1686 /* changed mpeaceful again; have to reset malign */
1689 if (m
->asleep
>= 0) {
1691 /* optimizer bug strikes again */
1693 mtmp
->msleeping
= 1;
1695 mtmp
->msleeping
= 0;
1697 mtmp
->msleeping
= m
->asleep
;
1701 mtmp
->mtrapseen
= m
->seentraps
;
1715 mtmp
->minvis
= mtmp
->perminvis
= 1;
1719 mtmp
->mblinded
= (m
->blinded
% 127);
1723 mtmp
->mfrozen
= (m
->paralyzed
% 127);
1727 mtmp
->mfleetim
= (m
->fleeing
% 127);
1730 if (m
->has_invent
) {
1731 discard_minvent(mtmp
);
1732 invent_carrying_monster
= mtmp
;
1738 * Create an object in a room.
1741 create_object(o
, croom
)
1743 struct mkroom
*croom
;
1748 boolean named
; /* has a name been supplied in level description? */
1750 named
= o
->name
.str
? TRUE
: FALSE
;
1752 get_location_coord(&x
, &y
, DRY
, croom
, o
->coord
);
1760 otmp
= mkobj_at(RANDOM_CLASS
, x
, y
, !named
);
1761 else if (o
->id
!= -1)
1762 otmp
= mksobj_at(o
->id
, x
, y
, TRUE
, !named
);
1765 * The special levels are compiled with the default "text" object
1766 * class characters. We must convert them to the internal format.
1768 char oclass
= (char) def_char_to_objclass(c
);
1770 if (oclass
== MAXOCLASSES
)
1771 panic("create_object: unexpected object class '%c'", c
);
1773 /* KMH -- Create piles of gold properly */
1774 if (oclass
== COIN_CLASS
)
1775 otmp
= mkgold(0L, x
, y
);
1777 otmp
= mkobj_at(oclass
, x
, y
, !named
);
1780 if (o
->spe
!= -127) /* That means NOT RANDOM! */
1781 otmp
->spe
= (schar
) o
->spe
;
1783 switch (o
->curse_state
) {
1786 break; /* BLESSED */
1790 break; /* uncursed */
1795 break; /* Otherwise it's random and we're happy
1796 * with what mkobj gave us! */
1799 /* corpsenm is "empty" if -1, random if -2, otherwise specific */
1800 if (o
->corpsenm
!= NON_PM
) {
1801 if (o
->corpsenm
== NON_PM
- 1)
1802 set_corpsenm(otmp
, rndmonnum());
1804 set_corpsenm(otmp
, o
->corpsenm
);
1806 /* set_corpsenm() took care of egg hatch and corpse timers */
1809 otmp
= oname(otmp
, o
->name
.str
);
1812 if (o
->eroded
< 0) {
1813 otmp
->oerodeproof
= 1;
1815 otmp
->oeroded
= (o
->eroded
% 4);
1816 otmp
->oeroded2
= ((o
->eroded
>> 2) % 4);
1820 otmp
->recharged
= (o
->recharged
% 8);
1823 } else if (o
->broken
) {
1825 otmp
->olocked
= 0; /* obj generation may set */
1827 if (o
->trapped
== 0 || o
->trapped
== 1)
1828 otmp
->otrapped
= o
->trapped
;
1831 #ifdef INVISIBLE_OBJECTS
1836 if (o
->quan
> 0 && objects
[otmp
->otyp
].oc_merge
) {
1837 otmp
->quan
= o
->quan
;
1838 otmp
->owt
= weight(otmp
);
1842 if (o
->containment
& SP_OBJ_CONTENT
) {
1843 if (!container_idx
) {
1844 if (!invent_carrying_monster
) {
1845 /*impossible("create_object: no container");*/
1846 /* don't complain, the monster may be gone legally
1847 (eg. unique demon already generated)
1848 TODO: In the case of unique demon lords, they should
1849 get their inventories even when they get generated
1850 outside the des-file. Maybe another data file that
1851 determines what inventories monsters get by default?
1855 struct obj
*objcheck
= otmp
;
1858 for (ci
= 0; ci
< container_idx
; ci
++)
1859 if (container_obj
[ci
] == objcheck
)
1861 remove_object(otmp
);
1862 if (mpickobj(invent_carrying_monster
, otmp
)) {
1865 "container given to monster was merged or deallocated.");
1866 for (ci
= inuse
; ci
< container_idx
- 1; ci
++)
1867 container_obj
[ci
] = container_obj
[ci
+ 1];
1868 container_obj
[container_idx
] = NULL
;
1871 /* we lost track of it. */
1876 remove_object(otmp
);
1877 if (container_obj
[container_idx
- 1])
1878 (void) add_to_container(container_obj
[container_idx
- 1],
1881 obj_extract_self(otmp
);
1888 if (o
->containment
& SP_OBJ_CONTAINER
) {
1889 delete_contents(otmp
);
1890 if (container_idx
< MAX_CONTAINMENT
) {
1891 container_obj
[container_idx
] = otmp
;
1894 impossible("create_object: too deeply nested containers.");
1897 /* Medusa level special case: statues are petrified monsters, so they
1898 * are not stone-resistant and have monster inventory. They also lack
1899 * other contents, but that can be specified as an empty container.
1901 if (o
->id
== STATUE
&& Is_medusa_level(&u
.uz
) && o
->corpsenm
== NON_PM
) {
1905 int i
= 0; /* prevent endless loop in case makemon always fails */
1907 /* Named random statues are of player types, and aren't stone-
1908 * resistant (if they were, we'd have to reset the name as well as
1909 * setting corpsenm).
1911 for (wastyp
= otmp
->corpsenm
; i
< 1000; i
++, wastyp
= rndmonnum()) {
1912 /* makemon without rndmonst() might create a group */
1913 was
= makemon(&mons
[wastyp
], 0, 0, MM_NOCOUNTBIRTH
);
1915 if (!resists_ston(was
)) {
1916 (void) propagate(wastyp
, TRUE
, FALSE
);
1924 set_corpsenm(otmp
, wastyp
);
1925 while (was
->minvent
) {
1928 obj_extract_self(obj
);
1929 (void) add_to_container(otmp
, obj
);
1931 otmp
->owt
= weight(otmp
);
1936 /* Nasty hack here: try to determine if this is the Mines or Sokoban
1937 * "prize" and then set record_achieve_special (maps to corpsenm)
1938 * for the object. That field will later be checked to find out if
1939 * the player obtained the prize. */
1940 if (otmp
->otyp
== LUCKSTONE
&& Is_mineend_level(&u
.uz
)) {
1941 otmp
->record_achieve_special
= 1;
1942 } else if ((otmp
->otyp
== AMULET_OF_REFLECTION
1943 || otmp
->otyp
== BAG_OF_HOLDING
)
1944 && Is_sokoend_level(&u
.uz
)) {
1945 otmp
->record_achieve_special
= 1;
1951 begin_burn(otmp
, FALSE
);
1957 (void) bury_an_obj(otmp
, &dealloced
);
1958 if (dealloced
&& container_idx
) {
1959 container_obj
[container_idx
- 1] = NULL
;
1965 * Create an altar in a room.
1968 create_altar(a
, croom
)
1970 struct mkroom
*croom
;
1974 boolean croom_is_temple
= TRUE
;
1978 get_free_room_loc(&x
, &y
, croom
, a
->coord
);
1979 if (croom
->rtype
!= TEMPLE
)
1980 croom_is_temple
= FALSE
;
1982 get_location_coord(&x
, &y
, DRY
, croom
, a
->coord
);
1983 if ((sproom
= (schar
) *in_rooms(x
, y
, TEMPLE
)) != 0)
1984 croom
= &rooms
[sproom
- ROOMOFFSET
];
1986 croom_is_temple
= FALSE
;
1989 /* check for existing features */
1990 oldtyp
= levl
[x
][y
].typ
;
1991 if (oldtyp
== STAIRS
|| oldtyp
== LADDER
)
1994 /* Is the alignment random ?
1995 * If so, it's an 80% chance that the altar will be co-aligned.
1997 * The alignment is encoded as amask values instead of alignment
1998 * values to avoid conflicting with the rest of the encoding,
1999 * shared by many other parts of the special level code.
2001 amask
= (a
->align
== AM_SPLEV_CO
)
2002 ? Align2amask(u
.ualignbase
[A_ORIGINAL
])
2003 : (a
->align
== AM_SPLEV_NONCO
)
2004 ? Align2amask(noncoalignment(u
.ualignbase
[A_ORIGINAL
]))
2005 : (a
->align
== -(MAX_REGISTERS
+ 1))
2007 : (a
->align
< 0 ? ralign
[-a
->align
- 1] : a
->align
);
2009 levl
[x
][y
].typ
= ALTAR
;
2010 levl
[x
][y
].altarmask
= amask
;
2013 a
->shrine
= rn2(2); /* handle random case */
2015 if (!croom_is_temple
|| !a
->shrine
)
2018 if (a
->shrine
) { /* Is it a shrine or sanctum? */
2019 priestini(&u
.uz
, croom
, x
, y
, (a
->shrine
> 1));
2020 levl
[x
][y
].altarmask
|= AM_SHRINE
;
2021 level
.flags
.has_temple
= TRUE
;
2026 replace_terrain(terr
, croom
)
2027 replaceterrain
*terr
;
2028 struct mkroom
*croom
;
2030 schar x
, y
, x1
, y1
, x2
, y2
;
2032 if (terr
->toter
>= MAX_TYPE
)
2037 get_location(&x1
, &y1
, ANY_LOC
, croom
);
2041 get_location(&x2
, &y2
, ANY_LOC
, croom
);
2043 for (x
= max(x1
, 0); x
<= min(x2
, COLNO
- 1); x
++)
2044 for (y
= max(y1
, 0); y
<= min(y2
, ROWNO
- 1); y
++)
2045 if (levl
[x
][y
].typ
== terr
->fromter
&& rn2(100) < terr
->chance
) {
2046 SET_TYPLIT(x
, y
, terr
->toter
, terr
->tolit
);
2051 * Search for a door in a room on a specified wall.
2054 search_door(croom
, x
, y
, wall
, cnt
)
2055 struct mkroom
*croom
;
2089 dx
= dy
= xx
= yy
= 0;
2090 panic("search_door: Bad wall!");
2093 while (xx
<= croom
->hx
+ 1 && yy
<= croom
->hy
+ 1) {
2094 if (IS_DOOR(levl
[xx
][yy
].typ
) || levl
[xx
][yy
].typ
== SDOOR
) {
2107 * Dig a corridor between two points.
2110 dig_corridor(org
, dest
, nxcor
, ftyp
, btyp
)
2115 int dx
= 0, dy
= 0, dix
, diy
, cct
;
2123 if (xx
<= 0 || yy
<= 0 || tx
<= 0 || ty
<= 0 || xx
> COLNO
- 1
2124 || tx
> COLNO
- 1 || yy
> ROWNO
- 1 || ty
> ROWNO
- 1) {
2125 debugpline4("dig_corridor: bad coords <%d,%d> <%d,%d>.",
2141 while (xx
!= tx
|| yy
!= ty
) {
2142 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
2143 if (cct
++ > 500 || (nxcor
&& !rn2(35)))
2149 if (xx
>= COLNO
- 1 || xx
<= 0 || yy
<= 0 || yy
>= ROWNO
- 1)
2150 return FALSE
; /* impossible */
2152 crm
= &levl
[xx
][yy
];
2153 if (crm
->typ
== btyp
) {
2154 if (ftyp
!= CORR
|| rn2(100)) {
2156 if (nxcor
&& !rn2(50))
2157 (void) mksobj_at(BOULDER
, xx
, yy
, TRUE
, FALSE
);
2161 } else if (crm
->typ
!= ftyp
&& crm
->typ
!= SCORR
) {
2166 /* find next corridor position */
2170 if ((dix
> diy
) && diy
&& !rn2(dix
-diy
+1)) {
2172 } else if ((diy
> dix
) && dix
&& !rn2(diy
-dix
+1)) {
2176 /* do we have to change direction ? */
2177 if (dy
&& dix
> diy
) {
2178 register int ddx
= (xx
> tx
) ? -1 : 1;
2180 crm
= &levl
[xx
+ ddx
][yy
];
2181 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
) {
2186 } else if (dx
&& diy
> dix
) {
2187 register int ddy
= (yy
> ty
) ? -1 : 1;
2189 crm
= &levl
[xx
][yy
+ ddy
];
2190 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
) {
2197 /* continue straight on? */
2198 crm
= &levl
[xx
+ dx
][yy
+ dy
];
2199 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
)
2202 /* no, what must we do now?? */
2205 dy
= (ty
< yy
) ? -1 : 1;
2208 dx
= (tx
< xx
) ? -1 : 1;
2210 crm
= &levl
[xx
+ dx
][yy
+ dy
];
2211 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
)
2220 * Disgusting hack: since special levels have their rooms filled before
2221 * sorting the rooms, we have to re-arrange the speed values upstairs_room
2222 * and dnstairs_room after the rooms have been sorted. On normal levels,
2223 * stairs don't get created until _after_ sorting takes place.
2229 struct mkroom
*croom
;
2232 && !((dnstairs_room
->lx
<= xdnstair
&& xdnstair
<= dnstairs_room
->hx
)
2233 && (dnstairs_room
->ly
<= ydnstair
2234 && ydnstair
<= dnstairs_room
->hy
))) {
2235 for (i
= 0; i
< nroom
; i
++) {
2237 if ((croom
->lx
<= xdnstair
&& xdnstair
<= croom
->hx
)
2238 && (croom
->ly
<= ydnstair
&& ydnstair
<= croom
->hy
)) {
2239 dnstairs_room
= croom
;
2244 panic("Couldn't find dnstair room in fix_stair_rooms!");
2247 && !((upstairs_room
->lx
<= xupstair
&& xupstair
<= upstairs_room
->hx
)
2248 && (upstairs_room
->ly
<= yupstair
2249 && yupstair
<= upstairs_room
->hy
))) {
2250 for (i
= 0; i
< nroom
; i
++) {
2252 if ((croom
->lx
<= xupstair
&& xupstair
<= croom
->hx
)
2253 && (croom
->ly
<= yupstair
&& yupstair
<= croom
->hy
)) {
2254 upstairs_room
= croom
;
2259 panic("Couldn't find upstair room in fix_stair_rooms!");
2264 * Corridors always start from a door. But it can end anywhere...
2265 * Basically we search for door coordinates or for endpoints coordinates
2266 * (from a distance).
2274 if (c
->src
.room
== -1) {
2276 makecorridors(); /*makecorridors(c->src.door);*/
2280 if (!search_door(&rooms
[c
->src
.room
], &org
.x
, &org
.y
, c
->src
.wall
,
2284 if (c
->dest
.room
!= -1) {
2285 if (!search_door(&rooms
[c
->dest
.room
], &dest
.x
, &dest
.y
, c
->dest
.wall
,
2288 switch (c
->src
.wall
) {
2302 switch (c
->dest
.wall
) {
2316 (void) dig_corridor(&org
, &dest
, FALSE
, CORR
, STONE
);
2321 * Fill a room (shop, zoo, etc...) with appropriate stuff.
2324 fill_room(croom
, prefilled
)
2325 struct mkroom
*croom
;
2328 if (!croom
|| croom
->rtype
== OROOM
)
2335 if (croom
->rtype
>= SHOPBASE
) {
2336 stock_room(croom
->rtype
- SHOPBASE
, croom
);
2337 level
.flags
.has_shop
= TRUE
;
2341 switch (croom
->rtype
) {
2343 for (x
= croom
->lx
; x
<= croom
->hx
; x
++)
2344 for (y
= croom
->ly
; y
<= croom
->hy
; y
++)
2345 (void) mkgold((long) rn1(abs(depth(&u
.uz
)) * 100, 51),
2357 switch (croom
->rtype
) {
2359 level
.flags
.has_vault
= TRUE
;
2362 level
.flags
.has_zoo
= TRUE
;
2365 level
.flags
.has_court
= TRUE
;
2368 level
.flags
.has_morgue
= TRUE
;
2371 level
.flags
.has_beehive
= TRUE
;
2374 level
.flags
.has_barracks
= TRUE
;
2377 level
.flags
.has_temple
= TRUE
;
2380 level
.flags
.has_swamp
= TRUE
;
2391 struct mkroom
*aroom
;
2392 xchar rtype
= (!r
->chance
|| rn2(100) < r
->chance
) ? r
->rtype
: OROOM
;
2395 aroom
= &subrooms
[nsubroom
];
2396 okroom
= create_subroom(mkr
, r
->x
, r
->y
, r
->w
, r
->h
, rtype
, r
->rlit
);
2398 aroom
= &rooms
[nroom
];
2399 okroom
= create_room(r
->x
, r
->y
, r
->w
, r
->h
, r
->xalign
, r
->yalign
,
2404 #ifdef SPECIALIZATION
2405 topologize(aroom
, FALSE
); /* set roomno */
2407 topologize(aroom
); /* set roomno */
2409 aroom
->needfill
= r
->filled
;
2410 aroom
->needjoining
= r
->joined
;
2413 return (struct mkroom
*) 0;
2417 * set lighting in a region that will not become a room.
2420 light_region(tmpregion
)
2423 register boolean litstate
= tmpregion
->rlit
? 1 : 0;
2424 register int hiy
= tmpregion
->y2
;
2426 register struct rm
*lev
;
2427 int lowy
= tmpregion
->y1
;
2428 int lowx
= tmpregion
->x1
, hix
= tmpregion
->x2
;
2431 /* adjust region size for walls, but only if lighted */
2432 lowx
= max(lowx
- 1, 1);
2433 hix
= min(hix
+ 1, COLNO
- 1);
2434 lowy
= max(lowy
- 1, 0);
2435 hiy
= min(hiy
+ 1, ROWNO
- 1);
2437 for (x
= lowx
; x
<= hix
; x
++) {
2438 lev
= &levl
[x
][lowy
];
2439 for (y
= lowy
; y
<= hiy
; y
++) {
2440 if (lev
->typ
!= LAVAPOOL
) /* this overrides normal lighting */
2441 lev
->lit
= litstate
;
2448 wallify_map(x1
, y1
, x2
, y2
)
2451 int x
, y
, xx
, yy
, lo_xx
, lo_yy
, hi_xx
, hi_yy
;
2453 for (y
= y1
; y
<= y2
; y
++) {
2454 lo_yy
= (y
> 0) ? y
- 1 : 0;
2455 hi_yy
= (y
< y2
) ? y
+ 1 : y2
;
2456 for (x
= x1
; x
<= x2
; x
++) {
2457 if (levl
[x
][y
].typ
!= STONE
)
2459 lo_xx
= (x
> 0) ? x
- 1 : 0;
2460 hi_xx
= (x
< x2
) ? x
+ 1 : x2
;
2461 for (yy
= lo_yy
; yy
<= hi_yy
; yy
++)
2462 for (xx
= lo_xx
; xx
<= hi_xx
; xx
++)
2463 if (IS_ROOM(levl
[xx
][yy
].typ
)
2464 || levl
[xx
][yy
].typ
== CROSSWALL
) {
2465 levl
[x
][y
].typ
= (yy
!= y
) ? HWALL
: VWALL
;
2466 yy
= hi_yy
; /* end `yy' loop */
2467 break; /* end `xx' loop */
2474 * Select a random coordinate in the maze.
2476 * We want a place not 'touched' by the loader. That is, a place in
2477 * the maze outside every part of the special level.
2480 maze1xy(m
, humidity
)
2484 register int x
, y
, tryct
= 2000;
2485 /* tryct: normally it won't take more than ten or so tries due
2486 to the circumstances under which we'll be called, but the
2487 `humidity' screening might drastically change the chances */
2490 x
= rn1(x_maze_max
- 3, 3);
2491 y
= rn1(y_maze_max
- 3, 3);
2493 break; /* give up */
2494 } while (!(x
% 2) || !(y
% 2) || SpLev_Map
[x
][y
]
2495 || !is_ok_location((schar
) x
, (schar
) y
, humidity
));
2497 m
->x
= (xchar
) x
, m
->y
= (xchar
) y
;
2501 * If there's a significant portion of maze unused by the special level,
2502 * we don't want it empty.
2504 * Makes the number of traps, monsters, etc. proportional
2505 * to the size of the maze.
2510 int mapcountmax
, mapcount
, mapfact
;
2514 mapcountmax
= mapcount
= (x_maze_max
- 2) * (y_maze_max
- 2);
2515 mapcountmax
= mapcountmax
/ 2;
2517 for (x
= 2; x
< x_maze_max
; x
++)
2518 for (y
= 0; y
< y_maze_max
; y
++)
2519 if (SpLev_Map
[x
][y
])
2522 if ((mapcount
> (int) (mapcountmax
/ 10))) {
2523 mapfact
= (int) ((mapcount
* 100L) / mapcountmax
);
2524 for (x
= rnd((int) (20 * mapfact
) / 100); x
; x
--) {
2526 (void) mkobj_at(rn2(2) ? GEM_CLASS
: RANDOM_CLASS
, mm
.x
, mm
.y
,
2529 for (x
= rnd((int) (12 * mapfact
) / 100); x
; x
--) {
2531 (void) mksobj_at(BOULDER
, mm
.x
, mm
.y
, TRUE
, FALSE
);
2533 for (x
= rn2(2); x
; x
--) {
2535 (void) makemon(&mons
[PM_MINOTAUR
], mm
.x
, mm
.y
, NO_MM_FLAGS
);
2537 for (x
= rnd((int) (12 * mapfact
) / 100); x
; x
--) {
2539 (void) makemon((struct permonst
*) 0, mm
.x
, mm
.y
, NO_MM_FLAGS
);
2541 for (x
= rn2((int) (15 * mapfact
) / 100); x
; x
--) {
2543 (void) mkgold(0L, mm
.x
, mm
.y
);
2545 for (x
= rn2((int) (15 * mapfact
) / 100); x
; x
--) {
2549 trytrap
= rndtrap();
2550 if (sobj_at(BOULDER
, mm
.x
, mm
.y
))
2551 while (trytrap
== PIT
|| trytrap
== SPIKED_PIT
2552 || trytrap
== TRAPDOOR
|| trytrap
== HOLE
)
2553 trytrap
= rndtrap();
2554 (void) maketrap(mm
.x
, mm
.y
, trytrap
);
2560 * special level loader
2563 sp_level_loader(fd
, lvl
)
2568 struct opvar
*opdat
;
2571 Fread((genericptr_t
) & (lvl
->n_opcodes
), 1, sizeof(lvl
->n_opcodes
), fd
);
2572 lvl
->opcodes
= (_opcode
*) alloc(sizeof(_opcode
) * (lvl
->n_opcodes
));
2574 while (n_opcode
< lvl
->n_opcodes
) {
2575 Fread((genericptr_t
) &lvl
->opcodes
[n_opcode
].opcode
, 1,
2576 sizeof(lvl
->opcodes
[n_opcode
].opcode
), fd
);
2577 opcode
= lvl
->opcodes
[n_opcode
].opcode
;
2581 if (opcode
< SPO_NULL
|| opcode
>= MAX_SP_OPCODES
)
2582 panic("sp_level_loader: impossible opcode %i.", opcode
);
2584 if (opcode
== SPO_PUSH
) {
2586 struct opvar
*ov
= (struct opvar
*) alloc(sizeof(struct opvar
));
2589 ov
->spovartyp
= SPO_NULL
;
2591 Fread((genericptr_t
) & (ov
->spovartyp
), 1, sizeof(ov
->spovartyp
),
2594 switch (ov
->spovartyp
) {
2599 case SPOVAR_MAPCHAR
:
2603 Fread((genericptr_t
) & (ov
->vardata
.l
), 1,
2604 sizeof(ov
->vardata
.l
), fd
);
2606 case SPOVAR_VARIABLE
:
2611 Fread((genericptr_t
) &nsize
, 1, sizeof(nsize
), fd
);
2612 opd
= (char *) alloc(nsize
+ 1);
2615 Fread(opd
, 1, nsize
, fd
);
2617 ov
->vardata
.str
= opd
;
2621 panic("sp_level_loader: unknown opvar type %i",
2626 lvl
->opcodes
[n_opcode
].opdat
= opdat
;
2633 /* Frees the memory allocated for special level creation structs */
2638 static const char nhFunc
[] = "sp_level_free";
2641 while (n_opcode
< lvl
->n_opcodes
) {
2642 int opcode
= lvl
->opcodes
[n_opcode
].opcode
;
2643 struct opvar
*opdat
= lvl
->opcodes
[n_opcode
].opdat
;
2645 if (opcode
< SPO_NULL
|| opcode
>= MAX_SP_OPCODES
)
2646 panic("sp_level_free: unknown opcode %i", opcode
);
2653 lvl
->opcodes
= NULL
;
2658 splev_initlev(linit
)
2661 switch (linit
->init_style
) {
2663 impossible("Unrecognized level init style.");
2667 case LVLINIT_SOLIDFILL
:
2668 if (linit
->lit
== -1)
2669 linit
->lit
= rn2(2);
2670 lvlfill_solid(linit
->filling
, linit
->lit
);
2672 case LVLINIT_MAZEGRID
:
2673 lvlfill_maze_grid(2, 0, x_maze_max
, y_maze_max
, linit
->filling
);
2679 if (linit
->lit
== -1)
2680 linit
->lit
= rn2(2);
2681 if (linit
->filling
> -1)
2682 lvlfill_solid(linit
->filling
, 0);
2683 linit
->icedpools
= icedpools
;
2693 struct sp_frame
*frame
=
2694 (struct sp_frame
*) alloc(sizeof(struct sp_frame
));
2697 frame
->variables
= NULL
;
2698 frame
->n_opcode
= execptr
;
2699 frame
->stack
= (struct splevstack
*) alloc(sizeof(struct splevstack
));
2700 splev_stack_init(frame
->stack
);
2706 struct sp_frame
*frame
;
2711 splev_stack_done(frame
->stack
);
2712 frame
->stack
= NULL
;
2714 if (frame
->variables
) {
2715 variable_list_del(frame
->variables
);
2716 frame
->variables
= NULL
;
2722 spo_frame_push(coder
)
2723 struct sp_coder
*coder
;
2725 struct sp_frame
*tmpframe
= frame_new(coder
->frame
->n_opcode
);
2727 tmpframe
->next
= coder
->frame
;
2728 coder
->frame
= tmpframe
;
2732 spo_frame_pop(coder
)
2733 struct sp_coder
*coder
;
2735 if (coder
->frame
&& coder
->frame
->next
) {
2736 struct sp_frame
*tmpframe
= coder
->frame
->next
;
2738 frame_del(coder
->frame
);
2739 coder
->frame
= tmpframe
;
2740 coder
->stack
= coder
->frame
->stack
;
2745 sp_code_jmpaddr(curpos
, jmpaddr
)
2746 long curpos
, jmpaddr
;
2748 return (curpos
+ jmpaddr
);
2753 struct sp_coder
*coder
;
2755 static const char nhFunc
[] = "spo_call";
2757 struct opvar
*params
;
2758 struct sp_frame
*tmpframe
;
2760 if (!OV_pop_i(addr
) || !OV_pop_i(params
))
2762 if (OV_i(params
) < 0)
2765 tmpframe
= frame_new(sp_code_jmpaddr(coder
->frame
->n_opcode
,
2768 while (OV_i(params
)-- > 0) {
2769 splev_stack_push(tmpframe
->stack
, splev_stack_getdat_any(coder
));
2771 splev_stack_reverse(tmpframe
->stack
);
2774 tmpframe
->next
= coder
->frame
;
2775 coder
->frame
= tmpframe
;
2783 struct sp_coder
*coder
;
2785 static const char nhFunc
[] = "spo_return";
2786 struct opvar
*params
;
2788 if (!coder
->frame
|| !coder
->frame
->next
)
2789 panic("return: no frame.");
2790 if (!OV_pop_i(params
))
2792 if (OV_i(params
) < 0)
2795 while (OV_i(params
)-- > 0) {
2796 splev_stack_push(coder
->frame
->next
->stack
,
2797 splev_stack_pop(coder
->stack
));
2801 if (coder
->frame
->next
) {
2802 struct sp_frame
*tmpframe
= coder
->frame
->next
;
2803 frame_del(coder
->frame
);
2804 coder
->frame
= tmpframe
;
2805 coder
->stack
= coder
->frame
->stack
;
2813 spo_end_moninvent(coder
)
2814 struct sp_coder
*coder UNUSED
;
2816 if (invent_carrying_monster
)
2817 m_dowear(invent_carrying_monster
, TRUE
);
2818 invent_carrying_monster
= NULL
;
2823 spo_pop_container(coder
)
2824 struct sp_coder
*coder UNUSED
;
2826 if (container_idx
> 0) {
2828 container_obj
[container_idx
] = NULL
;
2834 struct sp_coder
*coder
;
2836 static const char nhFunc
[] = "spo_message";
2847 old_n
= lev_message
? (strlen(lev_message
) + 1) : 0;
2850 levmsg
= (char *) alloc(old_n
+ n
+ 1);
2852 levmsg
[old_n
- 1] = '\n';
2854 (void) memcpy((genericptr_t
) levmsg
, (genericptr_t
) lev_message
,
2856 (void) memcpy((genericptr_t
) &levmsg
[old_n
], msg
, n
);
2857 levmsg
[old_n
+ n
] = '\0';
2859 lev_message
= levmsg
;
2865 struct sp_coder
*coder
;
2867 static const char nhFunc
[] = "spo_monster";
2869 struct opvar
*varparam
;
2870 struct opvar
*id
, *mcoord
, *has_inv
;
2873 tmpmons
.peaceful
= -1;
2874 tmpmons
.asleep
= -1;
2875 tmpmons
.name
.str
= (char *) 0;
2877 tmpmons
.appear_as
.str
= (char *) 0;
2878 tmpmons
.align
= -MAX_REGISTERS
- 2;
2881 tmpmons
.cancelled
= 0;
2882 tmpmons
.revived
= 0;
2884 tmpmons
.fleeing
= 0;
2885 tmpmons
.blinded
= 0;
2886 tmpmons
.paralyzed
= 0;
2887 tmpmons
.stunned
= 0;
2888 tmpmons
.confused
= 0;
2889 tmpmons
.seentraps
= 0;
2890 tmpmons
.has_invent
= 0;
2892 if (!OV_pop_i(has_inv
))
2895 if (!OV_pop_i(varparam
))
2898 while ((nparams
++ < (SP_M_V_END
+ 1)) && (OV_typ(varparam
) == SPOVAR_INT
)
2899 && (OV_i(varparam
) >= 0) && (OV_i(varparam
) < SP_M_V_END
)) {
2900 struct opvar
*parm
= NULL
;
2903 switch (OV_i(varparam
)) {
2905 if ((OV_typ(parm
) == SPOVAR_STRING
) && !tmpmons
.name
.str
)
2906 tmpmons
.name
.str
= dupstr(OV_s(parm
));
2909 if ((OV_typ(parm
) == SPOVAR_INT
) && !tmpmons
.appear_as
.str
) {
2910 tmpmons
.appear
= OV_i(parm
);
2913 tmpmons
.appear_as
.str
= dupstr(OV_s(parm
));
2917 if (OV_typ(parm
) == SPOVAR_INT
)
2918 tmpmons
.asleep
= OV_i(parm
);
2921 if (OV_typ(parm
) == SPOVAR_INT
)
2922 tmpmons
.align
= OV_i(parm
);
2924 case SP_M_V_PEACEFUL
:
2925 if (OV_typ(parm
) == SPOVAR_INT
)
2926 tmpmons
.peaceful
= OV_i(parm
);
2929 if (OV_typ(parm
) == SPOVAR_INT
)
2930 tmpmons
.female
= OV_i(parm
);
2933 if (OV_typ(parm
) == SPOVAR_INT
)
2934 tmpmons
.invis
= OV_i(parm
);
2936 case SP_M_V_CANCELLED
:
2937 if (OV_typ(parm
) == SPOVAR_INT
)
2938 tmpmons
.cancelled
= OV_i(parm
);
2940 case SP_M_V_REVIVED
:
2941 if (OV_typ(parm
) == SPOVAR_INT
)
2942 tmpmons
.revived
= OV_i(parm
);
2945 if (OV_typ(parm
) == SPOVAR_INT
)
2946 tmpmons
.avenge
= OV_i(parm
);
2948 case SP_M_V_FLEEING
:
2949 if (OV_typ(parm
) == SPOVAR_INT
)
2950 tmpmons
.fleeing
= OV_i(parm
);
2952 case SP_M_V_BLINDED
:
2953 if (OV_typ(parm
) == SPOVAR_INT
)
2954 tmpmons
.blinded
= OV_i(parm
);
2956 case SP_M_V_PARALYZED
:
2957 if (OV_typ(parm
) == SPOVAR_INT
)
2958 tmpmons
.paralyzed
= OV_i(parm
);
2960 case SP_M_V_STUNNED
:
2961 if (OV_typ(parm
) == SPOVAR_INT
)
2962 tmpmons
.stunned
= OV_i(parm
);
2964 case SP_M_V_CONFUSED
:
2965 if (OV_typ(parm
) == SPOVAR_INT
)
2966 tmpmons
.confused
= OV_i(parm
);
2968 case SP_M_V_SEENTRAPS
:
2969 if (OV_typ(parm
) == SPOVAR_INT
)
2970 tmpmons
.seentraps
= OV_i(parm
);
2973 nparams
= SP_M_V_END
+ 1;
2976 impossible("MONSTER with unknown variable param type!");
2980 if (OV_i(varparam
) != SP_M_V_END
) {
2981 opvar_free(varparam
);
2986 if (!OV_pop_c(mcoord
))
2987 panic("no monster coord?");
2989 if (!OV_pop_typ(id
, SPOVAR_MONST
))
2990 panic("no mon type");
2992 tmpmons
.id
= SP_MONST_PM(OV_i(id
));
2993 tmpmons
.class = SP_MONST_CLASS(OV_i(id
));
2994 tmpmons
.coord
= OV_i(mcoord
);
2995 tmpmons
.has_invent
= OV_i(has_inv
);
2997 create_monster(&tmpmons
, coder
->croom
);
2999 Free(tmpmons
.name
.str
);
3000 Free(tmpmons
.appear_as
.str
);
3003 opvar_free(has_inv
);
3004 opvar_free(varparam
);
3009 struct sp_coder
*coder
;
3011 static const char nhFunc
[] = "spo_object";
3014 struct opvar
*varparam
;
3015 struct opvar
*id
, *containment
;
3019 tmpobj
.curse_state
= -1;
3020 tmpobj
.corpsenm
= NON_PM
;
3021 tmpobj
.name
.str
= (char *) 0;
3027 tmpobj
.trapped
= -1;
3028 tmpobj
.recharged
= 0;
3032 tmpobj
.coord
= SP_COORD_PACK_RANDOM(0);
3034 if (!OV_pop_i(containment
))
3037 if (!OV_pop_i(varparam
))
3040 while ((nparams
++ < (SP_O_V_END
+ 1)) && (OV_typ(varparam
) == SPOVAR_INT
)
3041 && (OV_i(varparam
) >= 0) && (OV_i(varparam
) < SP_O_V_END
)) {
3044 switch (OV_i(varparam
)) {
3046 if ((OV_typ(parm
) == SPOVAR_STRING
) && !tmpobj
.name
.str
)
3047 tmpobj
.name
.str
= dupstr(OV_s(parm
));
3049 case SP_O_V_CORPSENM
:
3050 if (OV_typ(parm
) == SPOVAR_MONST
) {
3051 char monclass
= SP_MONST_CLASS(OV_i(parm
));
3052 int monid
= SP_MONST_PM(OV_i(parm
));
3054 if (monid
>= 0 && monid
< NUMMONS
) {
3055 tmpobj
.corpsenm
= monid
;
3056 break; /* we're done! */
3058 struct permonst
*pm
= (struct permonst
*) 0;
3059 if (def_char_to_monclass(monclass
) != MAXMCLASSES
) {
3060 pm
= mkclass(def_char_to_monclass(monclass
), G_NOGEN
);
3065 tmpobj
.corpsenm
= monsndx(pm
);
3070 if (OV_typ(parm
) == SPOVAR_INT
)
3071 tmpobj
.curse_state
= OV_i(parm
);
3074 if (OV_typ(parm
) == SPOVAR_INT
)
3075 tmpobj
.spe
= OV_i(parm
);
3078 if (OV_typ(parm
) == SPOVAR_INT
)
3079 tmpobj
.quan
= OV_i(parm
);
3082 if (OV_typ(parm
) == SPOVAR_INT
)
3083 tmpobj
.buried
= OV_i(parm
);
3086 if (OV_typ(parm
) == SPOVAR_INT
)
3087 tmpobj
.lit
= OV_i(parm
);
3090 if (OV_typ(parm
) == SPOVAR_INT
)
3091 tmpobj
.eroded
= OV_i(parm
);
3094 if (OV_typ(parm
) == SPOVAR_INT
)
3095 tmpobj
.locked
= OV_i(parm
);
3097 case SP_O_V_TRAPPED
:
3098 if (OV_typ(parm
) == SPOVAR_INT
)
3099 tmpobj
.trapped
= OV_i(parm
);
3101 case SP_O_V_RECHARGED
:
3102 if (OV_typ(parm
) == SPOVAR_INT
)
3103 tmpobj
.recharged
= OV_i(parm
);
3106 if (OV_typ(parm
) == SPOVAR_INT
)
3107 tmpobj
.invis
= OV_i(parm
);
3109 case SP_O_V_GREASED
:
3110 if (OV_typ(parm
) == SPOVAR_INT
)
3111 tmpobj
.greased
= OV_i(parm
);
3114 if (OV_typ(parm
) == SPOVAR_INT
)
3115 tmpobj
.broken
= OV_i(parm
);
3118 if (OV_typ(parm
) != SPOVAR_COORD
)
3119 panic("no coord for obj?");
3120 tmpobj
.coord
= OV_i(parm
);
3123 nparams
= SP_O_V_END
+ 1;
3126 impossible("OBJECT with unknown variable param type!");
3130 if (OV_i(varparam
) != SP_O_V_END
) {
3131 opvar_free(varparam
);
3136 if (!OV_pop_typ(id
, SPOVAR_OBJ
))
3137 panic("no obj type");
3139 tmpobj
.id
= SP_OBJ_TYP(OV_i(id
));
3140 tmpobj
.class = SP_OBJ_CLASS(OV_i(id
));
3141 tmpobj
.containment
= OV_i(containment
);
3143 quancnt
= (tmpobj
.id
> STRANGE_OBJECT
) ? tmpobj
.quan
: 0;
3146 create_object(&tmpobj
, coder
->croom
);
3148 } while ((quancnt
> 0) && ((tmpobj
.id
> STRANGE_OBJECT
)
3149 && !objects
[tmpobj
.id
].oc_merge
));
3151 Free(tmpobj
.name
.str
);
3152 opvar_free(varparam
);
3154 opvar_free(containment
);
3158 spo_level_flags(coder
)
3159 struct sp_coder
*coder
;
3161 static const char nhFunc
[] = "spo_level_flags";
3162 struct opvar
*flagdata
;
3165 if (!OV_pop_i(flagdata
))
3167 lflags
= OV_i(flagdata
);
3169 if (lflags
& NOTELEPORT
)
3170 level
.flags
.noteleport
= 1;
3171 if (lflags
& HARDFLOOR
)
3172 level
.flags
.hardfloor
= 1;
3173 if (lflags
& NOMMAP
)
3174 level
.flags
.nommap
= 1;
3175 if (lflags
& SHORTSIGHTED
)
3176 level
.flags
.shortsighted
= 1;
3177 if (lflags
& ARBOREAL
)
3178 level
.flags
.arboreal
= 1;
3179 if (lflags
& MAZELEVEL
)
3180 level
.flags
.is_maze_lev
= 1;
3181 if (lflags
& PREMAPPED
)
3182 coder
->premapped
= TRUE
;
3183 if (lflags
& SHROUD
)
3184 level
.flags
.hero_memory
= 0;
3185 if (lflags
& GRAVEYARD
)
3186 level
.flags
.graveyard
= 1;
3187 if (lflags
& ICEDPOOLS
)
3189 if (lflags
& SOLIDIFY
)
3190 coder
->solidify
= TRUE
;
3191 if (lflags
& CORRMAZE
)
3192 level
.flags
.corrmaze
= TRUE
;
3193 if (lflags
& CHECK_INACCESSIBLES
)
3194 coder
->check_inaccessibles
= TRUE
;
3196 opvar_free(flagdata
);
3200 spo_initlevel(coder
)
3201 struct sp_coder
*coder
;
3203 static const char nhFunc
[] = "spo_initlevel";
3205 struct opvar
*init_style
, *fg
, *bg
, *smoothed
, *joined
, *lit
, *walled
,
3208 if (!OV_pop_i(fg
) || !OV_pop_i(bg
) || !OV_pop_i(smoothed
)
3209 || !OV_pop_i(joined
) || !OV_pop_i(lit
) || !OV_pop_i(walled
)
3210 || !OV_pop_i(filling
) || !OV_pop_i(init_style
))
3213 splev_init_present
= TRUE
;
3215 init_lev
.init_style
= OV_i(init_style
);
3216 init_lev
.fg
= OV_i(fg
);
3217 init_lev
.bg
= OV_i(bg
);
3218 init_lev
.smoothed
= OV_i(smoothed
);
3219 init_lev
.joined
= OV_i(joined
);
3220 init_lev
.lit
= OV_i(lit
);
3221 init_lev
.walled
= OV_i(walled
);
3222 init_lev
.filling
= OV_i(filling
);
3224 coder
->lvl_is_joined
= OV_i(joined
);
3226 splev_initlev(&init_lev
);
3228 opvar_free(init_style
);
3231 opvar_free(smoothed
);
3235 opvar_free(filling
);
3239 spo_engraving(coder
)
3240 struct sp_coder
*coder
;
3242 static const char nhFunc
[] = "spo_engraving";
3243 struct opvar
*etyp
, *txt
, *ecoord
;
3246 if (!OV_pop_i(etyp
) || !OV_pop_s(txt
) || !OV_pop_c(ecoord
))
3249 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(ecoord
));
3250 make_engr_at(x
, y
, OV_s(txt
), 0L, OV_i(etyp
));
3258 spo_mineralize(coder
)
3259 struct sp_coder
*coder
;
3261 static const char nhFunc
[] = "spo_mineralize";
3262 struct opvar
*kelp_pool
, *kelp_moat
, *gold_prob
, *gem_prob
;
3264 if (!OV_pop_i(gem_prob
) || !OV_pop_i(gold_prob
) || !OV_pop_i(kelp_moat
)
3265 || !OV_pop_i(kelp_pool
))
3268 mineralize(OV_i(kelp_pool
), OV_i(kelp_moat
), OV_i(gold_prob
),
3269 OV_i(gem_prob
), TRUE
);
3271 opvar_free(gem_prob
);
3272 opvar_free(gold_prob
);
3273 opvar_free(kelp_moat
);
3274 opvar_free(kelp_pool
);
3279 struct sp_coder
*coder
;
3281 static const char nhFunc
[] = "spo_room";
3283 if (coder
->n_subroom
> MAX_NESTED_ROOMS
) {
3284 panic("Too deeply nested rooms?!");
3286 struct opvar
*rflags
, *h
, *w
, *yalign
, *xalign
, *y
, *x
, *rlit
,
3289 struct mkroom
*tmpcr
;
3291 if (!OV_pop_i(h
) || !OV_pop_i(w
) || !OV_pop_i(y
) || !OV_pop_i(x
)
3292 || !OV_pop_i(yalign
) || !OV_pop_i(xalign
) || !OV_pop_i(rflags
)
3293 || !OV_pop_i(rlit
) || !OV_pop_i(chance
) || !OV_pop_i(rtype
))
3296 tmproom
.x
= OV_i(x
);
3297 tmproom
.y
= OV_i(y
);
3298 tmproom
.w
= OV_i(w
);
3299 tmproom
.h
= OV_i(h
);
3300 tmproom
.xalign
= OV_i(xalign
);
3301 tmproom
.yalign
= OV_i(yalign
);
3302 tmproom
.rtype
= OV_i(rtype
);
3303 tmproom
.chance
= OV_i(chance
);
3304 tmproom
.rlit
= OV_i(rlit
);
3305 tmproom
.filled
= (OV_i(rflags
) & (1 << 0));
3306 /*tmproom.irregular = (OV_i(rflags) & (1 << 1));*/
3307 tmproom
.joined
= !(OV_i(rflags
) & (1 << 2));
3320 if (!coder
->failed_room
[coder
->n_subroom
- 1]) {
3321 tmpcr
= build_room(&tmproom
, coder
->croom
);
3323 coder
->tmproomlist
[coder
->n_subroom
] = tmpcr
;
3324 coder
->failed_room
[coder
->n_subroom
] = FALSE
;
3328 } /* failed to create parent room, so fail this too */
3330 coder
->tmproomlist
[coder
->n_subroom
] = (struct mkroom
*) 0;
3331 coder
->failed_room
[coder
->n_subroom
] = TRUE
;
3337 struct sp_coder
*coder
;
3339 if (coder
->n_subroom
> 1) {
3341 coder
->tmproomlist
[coder
->n_subroom
] = NULL
;
3342 coder
->failed_room
[coder
->n_subroom
] = TRUE
;
3344 /* no subroom, get out of top-level room */
3345 /* Need to ensure xstart/ystart/xsize/ysize have something sensible,
3346 in case there's some stuff to be created outside the outermost
3350 if (xsize
<= 1 && ysize
<= 1) {
3361 struct sp_coder
*coder
;
3363 static const char nhFunc
[] = "spo_stair";
3365 struct opvar
*up
, *scoord
;
3366 struct trap
*badtrap
;
3368 if (!OV_pop_i(up
) || !OV_pop_c(scoord
))
3371 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(scoord
));
3372 if ((badtrap
= t_at(x
, y
)) != 0)
3374 mkstairs(x
, y
, (char) OV_i(up
), coder
->croom
);
3375 SpLev_Map
[x
][y
] = 1;
3383 struct sp_coder
*coder
;
3385 static const char nhFunc
[] = "spo_ladder";
3387 struct opvar
*up
, *lcoord
;
3389 if (!OV_pop_i(up
) || !OV_pop_c(lcoord
))
3392 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(lcoord
));
3394 levl
[x
][y
].typ
= LADDER
;
3395 SpLev_Map
[x
][y
] = 1;
3399 levl
[x
][y
].ladder
= LA_UP
;
3403 levl
[x
][y
].ladder
= LA_DOWN
;
3411 struct sp_coder
*coder
;
3413 static const char nhFunc
[] = "spo_grave";
3414 struct opvar
*gcoord
, *typ
, *txt
;
3417 if (!OV_pop_i(typ
) || !OV_pop_s(txt
) || !OV_pop_c(gcoord
))
3420 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(gcoord
));
3422 if (isok(x
, y
) && !t_at(x
, y
)) {
3423 levl
[x
][y
].typ
= GRAVE
;
3424 switch (OV_i(typ
)) {
3426 make_grave(x
, y
, OV_s(txt
));
3429 make_grave(x
, y
, NULL
);
3444 struct sp_coder
*coder
;
3446 static const char nhFunc
[] = "spo_altar";
3447 struct opvar
*al
, *shrine
, *acoord
;
3450 if (!OV_pop_i(al
) || !OV_pop_i(shrine
) || !OV_pop_c(acoord
))
3453 tmpaltar
.coord
= OV_i(acoord
);
3454 tmpaltar
.align
= OV_i(al
);
3455 tmpaltar
.shrine
= OV_i(shrine
);
3457 create_altar(&tmpaltar
, coder
->croom
);
3466 struct sp_coder
*coder
;
3468 static const char nhFunc
[] = "spo_trap";
3470 struct opvar
*tcoord
;
3473 if (!OV_pop_i(type
) || !OV_pop_c(tcoord
))
3476 tmptrap
.coord
= OV_i(tcoord
);
3477 tmptrap
.type
= OV_i(type
);
3479 create_trap(&tmptrap
, coder
->croom
);
3486 struct sp_coder
*coder
;
3488 static const char nhFunc
[] = "spo_gold";
3489 struct opvar
*gcoord
, *amt
;
3493 if (!OV_pop_c(gcoord
) || !OV_pop_i(amt
))
3496 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(gcoord
));
3499 mkgold(amount
, x
, y
);
3506 struct sp_coder
*coder
;
3508 static const char nhFunc
[] = "spo_corridor";
3509 struct opvar
*deswall
, *desdoor
, *desroom
, *srcwall
, *srcdoor
, *srcroom
;
3512 if (!OV_pop_i(deswall
) || !OV_pop_i(desdoor
) || !OV_pop_i(desroom
)
3513 || !OV_pop_i(srcwall
) || !OV_pop_i(srcdoor
) || !OV_pop_i(srcroom
))
3516 tc
.src
.room
= OV_i(srcroom
);
3517 tc
.src
.door
= OV_i(srcdoor
);
3518 tc
.src
.wall
= OV_i(srcwall
);
3519 tc
.dest
.room
= OV_i(desroom
);
3520 tc
.dest
.door
= OV_i(desdoor
);
3521 tc
.dest
.wall
= OV_i(deswall
);
3523 create_corridor(&tc
);
3525 opvar_free(deswall
);
3526 opvar_free(desdoor
);
3527 opvar_free(desroom
);
3528 opvar_free(srcwall
);
3529 opvar_free(srcdoor
);
3530 opvar_free(srcroom
);
3534 selection_opvar(nbuf
)
3538 char buf
[(COLNO
* ROWNO
) + 1];
3541 (void) memset(buf
, 1, sizeof(buf
));
3542 buf
[(COLNO
* ROWNO
)] = '\0';
3543 ov
= opvar_new_str(buf
);
3545 ov
= opvar_new_str(nbuf
);
3547 ov
->spovartyp
= SPOVAR_SEL
;
3552 selection_getpoint(x
, y
, ov
)
3556 if (!ov
|| ov
->spovartyp
!= SPOVAR_SEL
)
3558 if (x
< 0 || y
< 0 || x
>= COLNO
|| y
>= ROWNO
)
3561 return (ov
->vardata
.str
[COLNO
* y
+ x
] - 1);
3565 selection_setpoint(x
, y
, ov
, c
)
3570 if (!ov
|| ov
->spovartyp
!= SPOVAR_SEL
)
3572 if (x
< 0 || y
< 0 || x
>= COLNO
|| y
>= ROWNO
)
3575 ov
->vardata
.str
[COLNO
* y
+ x
] = (char) (c
+ 1);
3585 ov
= selection_opvar((char *) 0);
3589 for (x
= 0; x
< COLNO
; x
++)
3590 for (y
= 0; y
< ROWNO
; y
++)
3591 if (!selection_getpoint(x
, y
, s
))
3592 selection_setpoint(x
, y
, ov
, 1);
3598 selection_logical_oper(s1
, s2
, oper
)
3599 struct opvar
*s1
, *s2
;
3605 ov
= selection_opvar((char *) 0);
3609 for (x
= 0; x
< COLNO
; x
++)
3610 for (y
= 0; y
< ROWNO
; y
++) {
3614 if (selection_getpoint(x
, y
, s1
)
3615 || selection_getpoint(x
, y
, s2
))
3616 selection_setpoint(x
, y
, ov
, 1);
3619 if (selection_getpoint(x
, y
, s1
)
3620 && selection_getpoint(x
, y
, s2
))
3621 selection_setpoint(x
, y
, ov
, 1);
3630 selection_filter_mapchar(ov
, mc
)
3637 struct opvar
*ret
= selection_opvar((char *) 0);
3639 if (!ov
|| !mc
|| !ret
)
3641 mapc
= SP_MAPCHAR_TYP(OV_i(mc
));
3642 lit
= SP_MAPCHAR_LIT(OV_i(mc
));
3643 for (x
= 0; x
< COLNO
; x
++)
3644 for (y
= 0; y
< ROWNO
; y
++)
3645 if (selection_getpoint(x
, y
, ov
) && (levl
[x
][y
].typ
== mapc
)) {
3649 selection_setpoint(x
, y
, ret
, 1);
3652 selection_setpoint(x
, y
, ret
, rn2(2));
3656 if (levl
[x
][y
].lit
== lit
)
3657 selection_setpoint(x
, y
, ret
, 1);
3665 selection_filter_percent(ov
, percent
)
3673 for (x
= 0; x
< COLNO
; x
++)
3674 for (y
= 0; y
< ROWNO
; y
++)
3675 if (selection_getpoint(x
, y
, ov
) && (rn2(100) >= percent
))
3676 selection_setpoint(x
, y
, ov
, 0);
3680 selection_rndcoord(ov
, x
, y
, removeit
)
3689 for (dx
= 0; dx
< COLNO
; dx
++)
3690 for (dy
= 0; dy
< ROWNO
; dy
++)
3691 if (isok(dx
, dy
) && selection_getpoint(dx
, dy
, ov
))
3696 for (dx
= 0; dx
< COLNO
; dx
++)
3697 for (dy
= 0; dy
< ROWNO
; dy
++)
3698 if (isok(dx
, dy
) && selection_getpoint(dx
, dy
, ov
)) {
3702 if (removeit
) selection_setpoint(dx
, dy
, ov
, 0);
3713 selection_do_grow(ov
, dir
)
3718 char tmp
[COLNO
][ROWNO
];
3720 if (ov
->spovartyp
!= SPOVAR_SEL
)
3725 (void) memset(tmp
, 0, sizeof(tmp
));
3727 for (x
= 0; x
< COLNO
; x
++)
3728 for (y
= 0; y
< ROWNO
; y
++) {
3730 if ((dir
& W_WEST
) && (x
> 0)
3731 && (selection_getpoint(x
- 1, y
, ov
)))
3733 if ((dir
& (W_WEST
| W_NORTH
)) && (x
> 0) && (y
> 0)
3734 && (selection_getpoint(x
- 1, y
- 1, ov
)))
3736 if ((dir
& W_NORTH
) && (y
> 0)
3737 && (selection_getpoint(x
, y
- 1, ov
)))
3739 if ((dir
& (W_NORTH
| W_EAST
)) && (y
> 0) && (x
< COLNO
- 1)
3740 && (selection_getpoint(x
+ 1, y
- 1, ov
)))
3742 if ((dir
& W_EAST
) && (x
< COLNO
- 1)
3743 && (selection_getpoint(x
+ 1, y
, ov
)))
3745 if ((dir
& (W_EAST
| W_SOUTH
)) && (x
< COLNO
- 1)
3746 && (y
< ROWNO
- 1) && (selection_getpoint(x
+ 1, y
+ 1, ov
)))
3748 if ((dir
& W_SOUTH
) && (y
< ROWNO
- 1)
3749 && (selection_getpoint(x
, y
+ 1, ov
)))
3751 if ((dir
& (W_SOUTH
| W_WEST
)) && (y
< ROWNO
- 1) && (x
> 0)
3752 && (selection_getpoint(x
- 1, y
+ 1, ov
)))
3758 for (x
= 0; x
< COLNO
; x
++)
3759 for (y
= 0; y
< ROWNO
; y
++)
3761 selection_setpoint(x
, y
, ov
, 1);
3764 STATIC_VAR
int FDECL((*selection_flood_check_func
), (int, int));
3765 STATIC_VAR schar floodfillchk_match_under_typ
;
3768 set_selection_floodfillchk(f
)
3769 int FDECL((*f
), (int, int));
3771 selection_flood_check_func
= f
;
3775 floodfillchk_match_under(x
,y
)
3778 return (floodfillchk_match_under_typ
== levl
[x
][y
].typ
);
3782 floodfillchk_match_accessible(x
, y
)
3785 return (ACCESSIBLE(levl
[x
][y
].typ
)
3786 || levl
[x
][y
].typ
== SDOOR
3787 || levl
[x
][y
].typ
== SCORR
);
3791 selection_floodfill(ov
, x
, y
, diagonals
)
3796 static const char nhFunc
[] = "selection_floodfill";
3797 struct opvar
*tmp
= selection_opvar((char *) 0);
3798 #define SEL_FLOOD_STACK (COLNO * ROWNO)
3799 #define SEL_FLOOD(nx, ny) \
3801 if (idx < SEL_FLOOD_STACK) { \
3806 panic(floodfill_stack_overrun); \
3808 #define SEL_FLOOD_CHKDIR(mx,my,sel) \
3809 if (isok((mx), (my)) \
3810 && (*selection_flood_check_func)((mx), (my)) \
3811 && !selection_getpoint((mx), (my), (sel))) \
3812 SEL_FLOOD((mx), (my))
3813 static const char floodfill_stack_overrun
[] = "floodfill stack overrun";
3815 xchar dx
[SEL_FLOOD_STACK
];
3816 xchar dy
[SEL_FLOOD_STACK
];
3818 if (selection_flood_check_func
== NULL
) {
3828 selection_setpoint(x
, y
, ov
, 1);
3829 selection_setpoint(x
, y
, tmp
, 1);
3831 SEL_FLOOD_CHKDIR((x
+ 1), y
, tmp
);
3832 SEL_FLOOD_CHKDIR((x
- 1), y
, tmp
);
3833 SEL_FLOOD_CHKDIR(x
, (y
+ 1), tmp
);
3834 SEL_FLOOD_CHKDIR(x
, (y
- 1), tmp
);
3836 SEL_FLOOD_CHKDIR((x
+ 1), (y
+ 1), tmp
);
3837 SEL_FLOOD_CHKDIR((x
- 1), (y
- 1), tmp
);
3838 SEL_FLOOD_CHKDIR((x
- 1), (y
+ 1), tmp
);
3839 SEL_FLOOD_CHKDIR((x
+ 1), (y
- 1), tmp
);
3843 #undef SEL_FLOOD_STACK
3844 #undef SEL_FLOOD_CHKDIR
3848 /* McIlroy's Ellipse Algorithm */
3850 selection_do_ellipse(ov
, xc
, yc
, a
, b
, filled
)
3852 int xc
, yc
, a
, b
, filled
;
3853 { /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
3855 long a2
= (long) a
* a
, b2
= (long) b
* b
;
3856 long crit1
= -(a2
/ 4 + a
% 2 + b2
);
3857 long crit2
= -(b2
/ 4 + b
% 2 + a2
);
3858 long crit3
= -(b2
/ 4 + b
% 2);
3859 long t
= -a2
* y
; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
3860 long dxt
= 2 * b2
* x
, dyt
= -2 * a2
* y
;
3861 long d2xt
= 2 * b2
, d2yt
= 2 * a2
;
3871 while (y
>= 0 && x
<= a
) {
3872 selection_setpoint(xc
+ x
, yc
+ y
, ov
, 1);
3873 if (x
!= 0 || y
!= 0)
3874 selection_setpoint(xc
- x
, yc
- y
, ov
, 1);
3875 if (x
!= 0 && y
!= 0) {
3876 selection_setpoint(xc
+ x
, yc
- y
, ov
, 1);
3877 selection_setpoint(xc
- x
, yc
+ y
, ov
, 1);
3879 if (t
+ b2
* x
<= crit1
/* e(x+1,y-1/2) <= 0 */
3880 || t
+ a2
* y
<= crit3
) { /* e(x+1/2,y) <= 0 */
3884 } else if (t
- a2
* y
> crit2
) { /* e(x+1/2,y-1) > 0 */
3898 while (y
>= 0 && x
<= a
) {
3899 if (t
+ b2
* x
<= crit1
/* e(x+1,y-1/2) <= 0 */
3900 || t
+ a2
* y
<= crit3
) { /* e(x+1/2,y) <= 0 */
3905 } else if (t
- a2
* y
> crit2
) { /* e(x+1/2,y-1) > 0 */
3906 for (i
= 0; i
< width
; i
++)
3907 selection_setpoint(xc
- x
+ i
, yc
- y
, ov
, 1);
3909 for (i
= 0; i
< width
; i
++)
3910 selection_setpoint(xc
- x
+ i
, yc
+ y
, ov
, 1);
3915 for (i
= 0; i
< width
; i
++)
3916 selection_setpoint(xc
- x
+ i
, yc
- y
, ov
, 1);
3918 for (i
= 0; i
< width
; i
++)
3919 selection_setpoint(xc
- x
+ i
, yc
+ y
, ov
, 1);
3932 /* distance from line segment (x1,y1, x2,y2) to point (x3,y3) */
3934 line_dist_coord(x1
, y1
, x2
, y2
, x3
, y3
)
3935 long x1
, y1
, x2
, y2
, x3
, y3
;
3939 long s
= px
* px
+ py
* py
;
3940 long x
, y
, dx
, dy
, dist
= 0;
3943 if (x1
== x2
&& y1
== y2
)
3944 return isqrt(dist2(x1
, y1
, x3
, y3
));
3946 lu
= ((x3
- x1
) * px
+ (y3
- y1
) * py
) / (float) s
;
3956 dist
= isqrt(dx
* dx
+ dy
* dy
);
3962 selection_do_gradient(ov
, x
, y
, x2
, y2
, gtyp
, mind
, maxd
, limit
)
3964 long x
, y
, x2
, y2
, gtyp
, mind
, maxd
, limit
;
3980 case SEL_GRADIENT_RADIAL
: {
3981 for (dx
= 0; dx
< COLNO
; dx
++)
3982 for (dy
= 0; dy
< ROWNO
; dy
++) {
3983 long d0
= line_dist_coord(x
, y
, x2
, y2
, dx
, dy
);
3984 if (d0
>= mind
&& (!limit
|| d0
<= maxd
)) {
3985 if (d0
- mind
> rn2(dofs
))
3986 selection_setpoint(dx
, dy
, ov
, 1);
3991 case SEL_GRADIENT_SQUARE
: {
3992 for (dx
= 0; dx
< COLNO
; dx
++)
3993 for (dy
= 0; dy
< ROWNO
; dy
++) {
3994 long d1
= line_dist_coord(x
, y
, x2
, y2
, x
, dy
);
3995 long d2
= line_dist_coord(x
, y
, x2
, y2
, dx
, y
);
3996 long d3
= line_dist_coord(x
, y
, x2
, y2
, x2
, dy
);
3997 long d4
= line_dist_coord(x
, y
, x2
, y2
, dx
, y2
);
3998 long d5
= line_dist_coord(x
, y
, x2
, y2
, dx
, dy
);
3999 long d0
= min(d5
, min(max(d1
, d2
), max(d3
, d4
)));
4001 if (d0
>= mind
&& (!limit
|| d0
<= maxd
)) {
4002 if (d0
- mind
> rn2(dofs
))
4003 selection_setpoint(dx
, dy
, ov
, 1);
4011 /* bresenham line algo */
4013 selection_do_line(x1
, y1
, x2
, y2
, ov
)
4014 schar x1
, y1
, x2
, y2
;
4017 int d0
, dx
, dy
, ai
, bi
, xi
, yi
;
4035 selection_setpoint(x1
, y1
, ov
, 1);
4048 selection_setpoint(x1
, y1
, ov
, 1);
4061 selection_setpoint(x1
, y1
, ov
, 1);
4067 selection_do_randline(x1
, y1
, x2
, y2
, rough
, rec
, ov
)
4068 schar x1
, y1
, x2
, y2
, rough
, rec
;
4078 if ((x2
== x1
) && (y2
== y1
)) {
4079 selection_setpoint(x1
, y1
, ov
, 1);
4083 if (rough
> max(abs(x2
- x1
), abs(y2
- y1
)))
4084 rough
= max(abs(x2
- x1
), abs(y2
- y1
));
4087 mx
= ((x1
+ x2
) / 2);
4088 my
= ((y1
+ y2
) / 2);
4091 dx
= (Rand() % rough
) - (rough
/ 2);
4092 dy
= (Rand() % rough
) - (rough
/ 2);
4093 mx
= ((x1
+ x2
) / 2) + dx
;
4094 my
= ((y1
+ y2
) / 2) + dy
;
4095 } while ((mx
> COLNO
- 1 || mx
< 0 || my
< 0 || my
> ROWNO
- 1));
4098 selection_setpoint(mx
, my
, ov
, 1);
4100 rough
= (rough
* 2) / 3;
4104 selection_do_randline(x1
, y1
, mx
, my
, rough
, rec
, ov
);
4105 selection_do_randline(mx
, my
, x2
, y2
, rough
, rec
, ov
);
4109 selection_iterate(ov
, func
, arg
)
4111 select_iter_func func
;
4116 /* yes, this is very naive, but it's not _that_ expensive. */
4117 for (x
= 0; x
< COLNO
; x
++)
4118 for (y
= 0; y
< ROWNO
; y
++)
4119 if (selection_getpoint(x
, y
, ov
))
4124 sel_set_ter(x
, y
, arg
)
4130 terr
= *(terrain
*) arg
;
4131 SET_TYPLIT(x
, y
, terr
.ter
, terr
.tlit
);
4132 /* handle doors and secret doors */
4133 if (levl
[x
][y
].typ
== SDOOR
|| IS_DOOR(levl
[x
][y
].typ
)) {
4134 if (levl
[x
][y
].typ
== SDOOR
)
4135 levl
[x
][y
].doormask
= D_CLOSED
;
4136 if (x
&& (IS_WALL(levl
[x
- 1][y
].typ
) || levl
[x
- 1][y
].horizontal
))
4137 levl
[x
][y
].horizontal
= 1;
4142 sel_set_feature(x
, y
, arg
)
4146 if (IS_FURNITURE(levl
[x
][y
].typ
))
4148 levl
[x
][y
].typ
= (*(int *) arg
);
4152 sel_set_door(dx
, dy
, arg
)
4156 xchar typ
= *(xchar
*) arg
;
4160 if (!IS_DOOR(levl
[x
][y
].typ
) && levl
[x
][y
].typ
!= SDOOR
)
4161 levl
[x
][y
].typ
= (typ
& D_SECRET
) ? SDOOR
: DOOR
;
4162 if (typ
& D_SECRET
) {
4167 levl
[x
][y
].doormask
= typ
;
4168 SpLev_Map
[x
][y
] = 1;
4173 struct sp_coder
*coder
;
4175 static const char nhFunc
[] = "spo_door";
4176 struct opvar
*msk
, *sel
;
4179 if (!OV_pop_i(msk
) || !OV_pop_typ(sel
, SPOVAR_SEL
))
4182 typ
= OV_i(msk
) == -1 ? rnddoor() : (xchar
) OV_i(msk
);
4184 selection_iterate(sel
, sel_set_door
, (genericptr_t
) &typ
);
4192 struct sp_coder
*coder
;
4194 static const char nhFunc
[] = "spo_feature";
4198 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
4201 switch (coder
->opcode
) {
4203 impossible("spo_feature called with wrong opcode %i.", coder
->opcode
);
4215 selection_iterate(sel
, sel_set_feature
, (genericptr_t
) &typ
);
4221 struct sp_coder
*coder
;
4223 static const char nhFunc
[] = "spo_terrain";
4225 struct opvar
*ter
, *sel
;
4227 if (!OV_pop_typ(ter
, SPOVAR_MAPCHAR
) || !OV_pop_typ(sel
, SPOVAR_SEL
))
4230 tmpterrain
.ter
= SP_MAPCHAR_TYP(OV_i(ter
));
4231 tmpterrain
.tlit
= SP_MAPCHAR_LIT(OV_i(ter
));
4232 selection_iterate(sel
, sel_set_ter
, (genericptr_t
) &tmpterrain
);
4239 spo_replace_terrain(coder
)
4240 struct sp_coder
*coder
;
4242 static const char nhFunc
[] = "spo_replace_terrain";
4244 struct opvar
*reg
, *from_ter
, *to_ter
, *chance
;
4246 if (!OV_pop_i(chance
) || !OV_pop_typ(to_ter
, SPOVAR_MAPCHAR
)
4247 || !OV_pop_typ(from_ter
, SPOVAR_MAPCHAR
) || !OV_pop_r(reg
))
4250 rt
.chance
= OV_i(chance
);
4251 rt
.tolit
= SP_MAPCHAR_LIT(OV_i(to_ter
));
4252 rt
.toter
= SP_MAPCHAR_TYP(OV_i(to_ter
));
4253 rt
.fromter
= SP_MAPCHAR_TYP(OV_i(from_ter
));
4254 /* TODO: use SP_MAPCHAR_LIT(OV_i(from_ter)) too */
4255 rt
.x1
= SP_REGION_X1(OV_i(reg
));
4256 rt
.y1
= SP_REGION_Y1(OV_i(reg
));
4257 rt
.x2
= SP_REGION_X2(OV_i(reg
));
4258 rt
.y2
= SP_REGION_Y2(OV_i(reg
));
4260 replace_terrain(&rt
, coder
->croom
);
4263 opvar_free(from_ter
);
4269 generate_way_out_method(nx
,ny
, ov
)
4273 static const char nhFunc
[] = "generate_way_out_method";
4274 const int escapeitems
[] = { PICK_AXE
,
4279 RIN_TELEPORTATION
};
4280 struct opvar
*ov2
= selection_opvar((char *) 0), *ov3
;
4284 selection_floodfill(ov2
, nx
, ny
, TRUE
);
4285 ov3
= opvar_clone(ov2
);
4287 /* try to make a secret door */
4288 while (selection_rndcoord(ov3
, &x
, &y
, TRUE
)) {
4289 if (isok(x
+1, y
) && !selection_getpoint(x
+1, y
, ov
)
4290 && IS_WALL(levl
[x
+1][y
].typ
)
4291 && isok(x
+2, y
) && selection_getpoint(x
+2, y
, ov
)
4292 && ACCESSIBLE(levl
[x
+2][y
].typ
)) {
4293 levl
[x
+1][y
].typ
= SDOOR
;
4296 if (isok(x
-1, y
) && !selection_getpoint(x
-1, y
, ov
)
4297 && IS_WALL(levl
[x
-1][y
].typ
)
4298 && isok(x
-2, y
) && selection_getpoint(x
-2, y
, ov
)
4299 && ACCESSIBLE(levl
[x
-2][y
].typ
)) {
4300 levl
[x
-1][y
].typ
= SDOOR
;
4303 if (isok(x
, y
+1) && !selection_getpoint(x
, y
+1, ov
)
4304 && IS_WALL(levl
[x
][y
+1].typ
)
4305 && isok(x
, y
+2) && selection_getpoint(x
, y
+2, ov
)
4306 && ACCESSIBLE(levl
[x
][y
+2].typ
)) {
4307 levl
[x
][y
+1].typ
= SDOOR
;
4310 if (isok(x
, y
-1) && !selection_getpoint(x
, y
-1, ov
)
4311 && IS_WALL(levl
[x
][y
-1].typ
)
4312 && isok(x
, y
-2) && selection_getpoint(x
, y
-2, ov
)
4313 && ACCESSIBLE(levl
[x
][y
-2].typ
)) {
4314 levl
[x
][y
-1].typ
= SDOOR
;
4319 /* try to make a hole or a trapdoor */
4320 if (Can_fall_thru(&u
.uz
)) {
4322 ov3
= opvar_clone(ov2
);
4323 while (selection_rndcoord(ov3
, &x
, &y
, TRUE
)) {
4324 if (maketrap(x
,y
, rn2(2) ? HOLE
: TRAPDOOR
))
4329 /* generate one of the escape items */
4330 if (selection_rndcoord(ov2
, &x
, &y
, FALSE
)) {
4331 mksobj_at(escapeitems
[rn2(SIZE(escapeitems
))], x
, y
, TRUE
, FALSE
);
4345 static const char nhFunc
[] = "ensure_way_out";
4346 struct opvar
*ov
= selection_opvar((char *) 0);
4347 struct trap
*ttmp
= ftrap
;
4351 set_selection_floodfillchk(floodfillchk_match_accessible
);
4353 if (xupstair
&& !selection_getpoint(xupstair
, yupstair
, ov
))
4354 selection_floodfill(ov
, xupstair
, yupstair
, TRUE
);
4355 if (xdnstair
&& !selection_getpoint(xdnstair
, ydnstair
, ov
))
4356 selection_floodfill(ov
, xdnstair
, ydnstair
, TRUE
);
4357 if (xupladder
&& !selection_getpoint(xupladder
, yupladder
, ov
))
4358 selection_floodfill(ov
, xupladder
, yupladder
, TRUE
);
4359 if (xdnladder
&& !selection_getpoint(xdnladder
, ydnladder
, ov
))
4360 selection_floodfill(ov
, xdnladder
, ydnladder
, TRUE
);
4363 if ((ttmp
->ttyp
== MAGIC_PORTAL
|| ttmp
->ttyp
== VIBRATING_SQUARE
4364 || ttmp
->ttyp
== HOLE
|| ttmp
->ttyp
== TRAPDOOR
)
4365 && !selection_getpoint(ttmp
->tx
, ttmp
->ty
, ov
))
4366 selection_floodfill(ov
, ttmp
->tx
, ttmp
->ty
, TRUE
);
4372 for (x
= 0; x
< COLNO
; x
++)
4373 for (y
= 0; y
< ROWNO
; y
++)
4374 if (ACCESSIBLE(levl
[x
][y
].typ
)
4375 && !selection_getpoint(x
, y
, ov
)) {
4376 if (generate_way_out_method(x
,y
, ov
))
4377 selection_floodfill(ov
, x
,y
, TRUE
);
4387 spo_levregion(coder
)
4388 struct sp_coder
*coder
;
4390 static const char nhFunc
[] = "spot_levregion";
4391 struct opvar
*rname
, *padding
, *rtype
, *del_islev
, *dy2
, *dx2
, *dy1
, *dx1
,
4392 *in_islev
, *iy2
, *ix2
, *iy1
, *ix1
;
4394 lev_region
*tmplregion
;
4396 if (!OV_pop_s(rname
) || !OV_pop_i(padding
) || !OV_pop_i(rtype
)
4397 || !OV_pop_i(del_islev
) || !OV_pop_i(dy2
) || !OV_pop_i(dx2
)
4398 || !OV_pop_i(dy1
) || !OV_pop_i(dx1
) || !OV_pop_i(in_islev
)
4399 || !OV_pop_i(iy2
) || !OV_pop_i(ix2
) || !OV_pop_i(iy1
)
4403 tmplregion
= (lev_region
*) alloc(sizeof(lev_region
));
4405 tmplregion
->inarea
.x1
= OV_i(ix1
);
4406 tmplregion
->inarea
.y1
= OV_i(iy1
);
4407 tmplregion
->inarea
.x2
= OV_i(ix2
);
4408 tmplregion
->inarea
.y2
= OV_i(iy2
);
4410 tmplregion
->delarea
.x1
= OV_i(dx1
);
4411 tmplregion
->delarea
.y1
= OV_i(dy1
);
4412 tmplregion
->delarea
.x2
= OV_i(dx2
);
4413 tmplregion
->delarea
.y2
= OV_i(dy2
);
4415 tmplregion
->in_islev
= OV_i(in_islev
);
4416 tmplregion
->del_islev
= OV_i(del_islev
);
4417 tmplregion
->rtype
= OV_i(rtype
);
4418 tmplregion
->padding
= OV_i(padding
);
4419 tmplregion
->rname
.str
= dupstr(OV_s(rname
));
4421 if (!tmplregion
->in_islev
) {
4422 get_location(&tmplregion
->inarea
.x1
, &tmplregion
->inarea
.y1
, ANY_LOC
,
4423 (struct mkroom
*) 0);
4424 get_location(&tmplregion
->inarea
.x2
, &tmplregion
->inarea
.y2
, ANY_LOC
,
4425 (struct mkroom
*) 0);
4428 if (!tmplregion
->del_islev
) {
4429 get_location(&tmplregion
->delarea
.x1
, &tmplregion
->delarea
.y1
,
4430 ANY_LOC
, (struct mkroom
*) 0);
4431 get_location(&tmplregion
->delarea
.x2
, &tmplregion
->delarea
.y2
,
4432 ANY_LOC
, (struct mkroom
*) 0);
4435 /* realloc the lregion space to add the new one */
4436 lev_region
*newl
= (lev_region
*) alloc(
4437 sizeof(lev_region
) * (unsigned) (1 + num_lregions
));
4439 (void) memcpy((genericptr_t
) (newl
), (genericptr_t
) lregions
,
4440 sizeof(lev_region
) * num_lregions
);
4446 lregions
= (lev_region
*) alloc(sizeof(lev_region
));
4448 (void) memcpy(&lregions
[num_lregions
- 1], tmplregion
,
4449 sizeof(lev_region
));
4462 opvar_free(del_islev
);
4463 opvar_free(in_islev
);
4466 opvar_free(padding
);
4471 struct sp_coder
*coder
;
4473 static const char nhFunc
[] = "spo_region";
4474 struct opvar
*rtype
, *rlit
, *rflags
, *area
;
4475 xchar dx1
, dy1
, dx2
, dy2
;
4476 register struct mkroom
*troom
;
4477 boolean prefilled
, room_not_needed
, irregular
, joined
;
4479 if (!OV_pop_i(rflags
) || !OV_pop_i(rtype
) || !OV_pop_i(rlit
)
4483 prefilled
= !(OV_i(rflags
) & (1 << 0));
4484 irregular
= (OV_i(rflags
) & (1 << 1));
4485 joined
= !(OV_i(rflags
) & (1 << 2));
4487 if (OV_i(rtype
) > MAXRTYPE
) {
4488 OV_i(rtype
) -= MAXRTYPE
+ 1;
4495 (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? TRUE
: FALSE
;
4497 dx1
= SP_REGION_X1(OV_i(area
));
4498 dy1
= SP_REGION_Y1(OV_i(area
));
4499 dx2
= SP_REGION_X2(OV_i(area
));
4500 dy2
= SP_REGION_Y2(OV_i(area
));
4502 get_location(&dx1
, &dy1
, ANY_LOC
, (struct mkroom
*) 0);
4503 get_location(&dx2
, &dy2
, ANY_LOC
, (struct mkroom
*) 0);
4505 /* for an ordinary room, `prefilled' is a flag to force
4506 an actual room to be created (such rooms are used to
4507 control placement of migrating monster arrivals) */
4508 room_not_needed
= (OV_i(rtype
) == OROOM
&& !irregular
&& !prefilled
);
4509 if (room_not_needed
|| nroom
>= MAXNROFROOMS
) {
4511 if (!room_not_needed
)
4512 impossible("Too many rooms on new level!");
4513 tmpregion
.rlit
= OV_i(rlit
);
4518 light_region(&tmpregion
);
4528 troom
= &rooms
[nroom
];
4530 /* mark rooms that must be filled, but do it later */
4531 if (OV_i(rtype
) != OROOM
)
4532 troom
->needfill
= (prefilled
? 2 : 1);
4534 troom
->needjoining
= joined
;
4537 min_rx
= max_rx
= dx1
;
4538 min_ry
= max_ry
= dy1
;
4539 smeq
[nroom
] = nroom
;
4540 flood_fill_rm(dx1
, dy1
, nroom
+ ROOMOFFSET
, OV_i(rlit
), TRUE
);
4541 add_room(min_rx
, min_ry
, max_rx
, max_ry
, FALSE
, OV_i(rtype
), TRUE
);
4542 troom
->rlit
= OV_i(rlit
);
4543 troom
->irregular
= TRUE
;
4545 add_room(dx1
, dy1
, dx2
, dy2
, OV_i(rlit
), OV_i(rtype
), TRUE
);
4546 #ifdef SPECIALIZATION
4547 topologize(troom
, FALSE
); /* set roomno */
4549 topologize(troom
); /* set roomno */
4553 if (!room_not_needed
) {
4554 if (coder
->n_subroom
> 1)
4555 impossible("region as subroom");
4557 coder
->tmproomlist
[coder
->n_subroom
] = troom
;
4558 coder
->failed_room
[coder
->n_subroom
] = FALSE
;
4570 spo_drawbridge(coder
)
4571 struct sp_coder
*coder
;
4573 static const char nhFunc
[] = "spo_drawbridge";
4575 struct opvar
*dir
, *db_open
, *dcoord
;
4577 if (!OV_pop_i(dir
) || !OV_pop_i(db_open
) || !OV_pop_c(dcoord
))
4580 get_location_coord(&x
, &y
, DRY
| WET
| HOT
, coder
->croom
, OV_i(dcoord
));
4581 if (!create_drawbridge(x
, y
, OV_i(dir
), OV_i(db_open
)))
4582 impossible("Cannot create drawbridge.");
4583 SpLev_Map
[x
][y
] = 1;
4586 opvar_free(db_open
);
4592 struct sp_coder
*coder
;
4594 static const char nhFunc
[] = "spo_mazewalk";
4596 struct opvar
*ftyp
, *fstocked
, *fdir
, *mcoord
;
4599 if (!OV_pop_i(ftyp
) || !OV_pop_i(fstocked
) || !OV_pop_i(fdir
)
4600 || !OV_pop_c(mcoord
))
4605 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(mcoord
));
4609 if (OV_i(ftyp
) < 1) {
4610 OV_i(ftyp
) = level
.flags
.corrmaze
? CORR
: ROOM
;
4613 /* don't use move() - it doesn't use W_NORTH, etc. */
4628 impossible("spo_mazewalk: Bad MAZEWALK direction");
4631 if (!IS_DOOR(levl
[x
][y
].typ
)) {
4632 levl
[x
][y
].typ
= OV_i(ftyp
);
4633 levl
[x
][y
].flags
= 0;
4637 * We must be sure that the parity of the coordinates for
4638 * walkfrom() is odd. But we must also take into account
4639 * what direction was chosen.
4647 /* no need for IS_DOOR check; out of map bounds */
4648 levl
[x
][y
].typ
= OV_i(ftyp
);
4649 levl
[x
][y
].flags
= 0;
4659 walkfrom(x
, y
, OV_i(ftyp
));
4665 opvar_free(fstocked
);
4670 spo_wall_property(coder
)
4671 struct sp_coder
*coder
;
4673 static const char nhFunc
[] = "spo_wall_property";
4675 xchar dx1
, dy1
, dx2
, dy2
;
4676 int wprop
= (coder
->opcode
== SPO_NON_DIGGABLE
)
4683 dx1
= SP_REGION_X1(OV_i(r
));
4684 dy1
= SP_REGION_Y1(OV_i(r
));
4685 dx2
= SP_REGION_X2(OV_i(r
));
4686 dy2
= SP_REGION_Y2(OV_i(r
));
4688 get_location(&dx1
, &dy1
, ANY_LOC
, (struct mkroom
*) 0);
4689 get_location(&dx2
, &dy2
, ANY_LOC
, (struct mkroom
*) 0);
4691 set_wall_property(dx1
, dy1
, dx2
, dy2
, wprop
);
4697 spo_room_door(coder
)
4698 struct sp_coder
*coder
;
4700 static const char nhFunc
[] = "spo_room_door";
4701 struct opvar
*wall
, *secret
, *mask
, *pos
;
4704 if (!OV_pop_i(wall
) || !OV_pop_i(secret
) || !OV_pop_i(mask
)
4705 || !OV_pop_i(pos
) || !coder
->croom
)
4708 tmpd
.secret
= OV_i(secret
);
4709 tmpd
.mask
= OV_i(mask
);
4710 tmpd
.pos
= OV_i(pos
);
4711 tmpd
.wall
= OV_i(wall
);
4713 create_door(&tmpd
, coder
->croom
);
4723 sel_set_wallify(x
, y
, arg
)
4725 genericptr_t arg UNUSED
;
4727 wallify_map(x
, y
, x
, y
);
4732 struct sp_coder
*coder
;
4734 static const char nhFunc
[] = "spo_wallify";
4735 struct opvar
*typ
, *r
;
4736 int dx1
, dy1
, dx2
, dy2
;
4740 switch (OV_i(typ
)) {
4745 dx1
= (xchar
) SP_REGION_X1(OV_i(r
));
4746 dy1
= (xchar
) SP_REGION_Y1(OV_i(r
));
4747 dx2
= (xchar
) SP_REGION_X2(OV_i(r
));
4748 dy2
= (xchar
) SP_REGION_Y2(OV_i(r
));
4749 wallify_map(dx1
< 0 ? (xstart
-1) : dx1
, dy1
< 0 ? (ystart
-1) : dy1
,
4750 dx2
< 0 ? (xstart
+ xsize
+ 1) : dx2
,
4751 dy2
< 0 ? (ystart
+ ysize
+ 1) : dy2
);
4754 if (!OV_pop_typ(r
, SPOVAR_SEL
))
4756 selection_iterate(r
, sel_set_wallify
, NULL
);
4765 struct sp_coder
*coder
;
4767 static const char nhFunc
[] = "spo_map";
4768 mazepart tmpmazepart
;
4769 struct opvar
*mpxs
, *mpys
, *mpmap
, *mpa
, *mpkeepr
, *mpzalign
;
4770 xchar halign
, valign
;
4771 xchar tmpxstart
, tmpystart
, tmpxsize
, tmpysize
;
4774 if (!OV_pop_i(mpxs
) || !OV_pop_i(mpys
) || !OV_pop_s(mpmap
)
4775 || !OV_pop_i(mpkeepr
) || !OV_pop_i(mpzalign
) || !OV_pop_c(mpa
))
4778 tmpmazepart
.xsize
= OV_i(mpxs
);
4779 tmpmazepart
.ysize
= OV_i(mpys
);
4780 tmpmazepart
.zaligntyp
= OV_i(mpzalign
);
4782 upc
= get_unpacked_coord(OV_i(mpa
), ANY_LOC
);
4783 tmpmazepart
.halign
= upc
.x
;
4784 tmpmazepart
.valign
= upc
.y
;
4791 halign
= tmpmazepart
.halign
;
4792 valign
= tmpmazepart
.valign
;
4793 xsize
= tmpmazepart
.xsize
;
4794 ysize
= tmpmazepart
.ysize
;
4795 switch (tmpmazepart
.zaligntyp
) {
4800 switch ((int) halign
) {
4802 xstart
= splev_init_present
? 1 : 3;
4805 xstart
= 2 + ((x_maze_max
- 2 - xsize
) / 4);
4808 xstart
= 2 + ((x_maze_max
- 2 - xsize
) / 2);
4811 xstart
= 2 + ((x_maze_max
- 2 - xsize
) * 3 / 4);
4814 xstart
= x_maze_max
- xsize
- 1;
4817 switch ((int) valign
) {
4822 ystart
= 2 + ((y_maze_max
- 2 - ysize
) / 2);
4825 ystart
= y_maze_max
- ysize
- 1;
4834 if (!coder
->croom
) {
4837 xsize
= COLNO
- 1 - tmpmazepart
.xsize
;
4838 ysize
= ROWNO
- tmpmazepart
.ysize
;
4840 get_location_coord(&halign
, &valign
, ANY_LOC
, coder
->croom
,
4842 xsize
= tmpmazepart
.xsize
;
4843 ysize
= tmpmazepart
.ysize
;
4848 if ((ystart
< 0) || (ystart
+ ysize
> ROWNO
)) {
4849 /* try to move the start a bit */
4850 ystart
+= (ystart
> 0) ? -2 : 2;
4853 if (ystart
< 0 || ystart
+ ysize
> ROWNO
)
4854 panic("reading special level with ysize too large");
4856 if (xsize
<= 1 && ysize
<= 1) {
4864 for (y
= ystart
; y
< ystart
+ ysize
; y
++)
4865 for (x
= xstart
; x
< xstart
+ xsize
; x
++) {
4867 (mpmap
->vardata
.str
[(y
- ystart
) * xsize
+ (x
- xstart
)]
4869 if (mptyp
>= MAX_TYPE
)
4871 levl
[x
][y
].typ
= mptyp
;
4872 levl
[x
][y
].lit
= FALSE
;
4873 /* clear out levl: load_common_data may set them */
4874 levl
[x
][y
].flags
= 0;
4875 levl
[x
][y
].horizontal
= 0;
4876 levl
[x
][y
].roomno
= 0;
4877 levl
[x
][y
].edge
= 0;
4878 SpLev_Map
[x
][y
] = 1;
4880 * Set secret doors to closed (why not trapped too?). Set
4881 * the horizontal bit.
4883 if (levl
[x
][y
].typ
== SDOOR
|| IS_DOOR(levl
[x
][y
].typ
)) {
4884 if (levl
[x
][y
].typ
== SDOOR
)
4885 levl
[x
][y
].doormask
= D_CLOSED
;
4887 * If there is a wall to the left that connects to a
4888 * (secret) door, then it is horizontal. This does
4889 * not allow (secret) doors to be corners of rooms.
4891 if (x
!= xstart
&& (IS_WALL(levl
[x
- 1][y
].typ
)
4892 || levl
[x
- 1][y
].horizontal
))
4893 levl
[x
][y
].horizontal
= 1;
4894 } else if (levl
[x
][y
].typ
== HWALL
4895 || levl
[x
][y
].typ
== IRONBARS
)
4896 levl
[x
][y
].horizontal
= 1;
4897 else if (levl
[x
][y
].typ
== LAVAPOOL
)
4899 else if (splev_init_present
&& levl
[x
][y
].typ
== ICE
)
4900 levl
[x
][y
].icedpool
= icedpools
? ICED_POOL
: ICED_MOAT
;
4902 if (coder
->lvl_is_joined
)
4903 remove_rooms(xstart
, ystart
, xstart
+ xsize
, ystart
+ ysize
);
4905 if (!OV_i(mpkeepr
)) {
4916 opvar_free(mpkeepr
);
4917 opvar_free(mpzalign
);
4922 struct sp_coder
*coder
;
4925 static const char nhFunc
[] = "spo_jmp";
4929 if (!OV_pop_i(tmpa
))
4931 a
= sp_code_jmpaddr(coder
->frame
->n_opcode
, (OV_i(tmpa
) - 1));
4932 if ((a
>= 0) && (a
< lvl
->n_opcodes
) && (a
!= coder
->frame
->n_opcode
))
4933 coder
->frame
->n_opcode
= a
;
4938 spo_conditional_jump(coder
, lvl
)
4939 struct sp_coder
*coder
;
4942 static const char nhFunc
[] = "spo_conditional_jump";
4943 struct opvar
*oa
, *oc
;
4947 if (!OV_pop_i(oa
) || !OV_pop_i(oc
))
4950 a
= sp_code_jmpaddr(coder
->frame
->n_opcode
, (OV_i(oa
) - 1));
4953 switch (coder
->opcode
) {
4955 impossible("spo_conditional_jump: illegal opcode");
4958 test
= (c
& SP_CPUFLAG_LT
);
4961 test
= (c
& (SP_CPUFLAG_LT
| SP_CPUFLAG_EQ
));
4964 test
= (c
& SP_CPUFLAG_GT
);
4967 test
= (c
& (SP_CPUFLAG_GT
| SP_CPUFLAG_EQ
));
4970 test
= (c
& SP_CPUFLAG_EQ
);
4973 test
= (c
& ~SP_CPUFLAG_EQ
);
4977 if ((test
) && (a
>= 0) && (a
< lvl
->n_opcodes
)
4978 && (a
!= coder
->frame
->n_opcode
))
4979 coder
->frame
->n_opcode
= a
;
4987 struct sp_coder
*coder
;
4989 static const char nhFunc
[] = "spo_var_init";
4990 struct opvar
*vname
;
4991 struct opvar
*arraylen
;
4992 struct opvar
*vvalue
;
4993 struct splev_var
*tmpvar
;
4994 struct splev_var
*tmp2
;
5000 if (!vname
|| !arraylen
)
5001 panic("no values for SPO_VAR_INIT");
5003 tmpvar
= opvar_var_defined(coder
, OV_s(vname
));
5006 /* variable redefinition */
5007 if (OV_i(arraylen
) < 0) {
5009 if (tmpvar
->array_len
) {
5010 idx
= tmpvar
->array_len
;
5012 opvar_free(tmpvar
->data
.arrayvalues
[idx
]);
5014 Free(tmpvar
->data
.arrayvalues
);
5016 opvar_free(tmpvar
->data
.value
);
5018 tmpvar
->data
.arrayvalues
= NULL
;
5020 } else if (OV_i(arraylen
)) {
5021 /* redefined array */
5022 idx
= tmpvar
->array_len
;
5024 opvar_free(tmpvar
->data
.arrayvalues
[idx
]);
5026 Free(tmpvar
->data
.arrayvalues
);
5027 tmpvar
->data
.arrayvalues
= NULL
;
5028 goto create_new_array
;
5030 /* redefined single value */
5032 if (tmpvar
->svtyp
!= vvalue
->spovartyp
)
5033 panic("redefining variable as different type");
5034 opvar_free(tmpvar
->data
.value
);
5035 tmpvar
->data
.value
= vvalue
;
5036 tmpvar
->array_len
= 0;
5039 /* new variable definition */
5040 tmpvar
= (struct splev_var
*) alloc(sizeof(struct splev_var
));
5041 tmpvar
->next
= coder
->frame
->variables
;
5042 tmpvar
->name
= dupstr(OV_s(vname
));
5043 coder
->frame
->variables
= tmpvar
;
5045 if (OV_i(arraylen
) < 0) {
5049 tmp2
= opvar_var_defined(coder
, OV_s(vvalue
));
5051 panic("no copyable var");
5052 tmpvar
->svtyp
= tmp2
->svtyp
;
5053 tmpvar
->array_len
= tmp2
->array_len
;
5054 if (tmpvar
->array_len
) {
5055 idx
= tmpvar
->array_len
;
5056 tmpvar
->data
.arrayvalues
=
5057 (struct opvar
**) alloc(sizeof(struct opvar
*) * idx
);
5059 tmpvar
->data
.arrayvalues
[idx
] =
5060 opvar_clone(tmp2
->data
.arrayvalues
[idx
]);
5063 tmpvar
->data
.value
= opvar_clone(tmp2
->data
.value
);
5066 } else if (OV_i(arraylen
)) {
5069 idx
= OV_i(arraylen
);
5070 tmpvar
->array_len
= idx
;
5071 tmpvar
->data
.arrayvalues
=
5072 (struct opvar
**) alloc(sizeof(struct opvar
*) * idx
);
5076 panic("no value for arrayvariable");
5077 tmpvar
->data
.arrayvalues
[idx
] = vvalue
;
5079 tmpvar
->svtyp
= SPOVAR_ARRAY
;
5081 /* new single value */
5084 panic("no value for variable");
5085 tmpvar
->svtyp
= OV_typ(vvalue
);
5086 tmpvar
->data
.value
= vvalue
;
5087 tmpvar
->array_len
= 0;
5092 opvar_free(arraylen
);
5098 opvar_array_length(coder
)
5099 struct sp_coder
*coder
;
5101 static const char nhFunc
[] = "opvar_array_length";
5102 struct opvar
*vname
;
5103 struct splev_var
*tmp
;
5109 vname
= splev_stack_pop(coder
->stack
);
5112 if (vname
->spovartyp
!= SPOVAR_VARIABLE
)
5115 tmp
= coder
->frame
->variables
;
5117 if (!strcmp(tmp
->name
, OV_s(vname
))) {
5118 if ((tmp
->svtyp
& SPOVAR_ARRAY
)) {
5119 len
= tmp
->array_len
;
5135 spo_shuffle_array(coder
)
5136 struct sp_coder
*coder
;
5138 static const char nhFunc
[] = "spo_shuffle_array";
5139 struct opvar
*vname
;
5140 struct splev_var
*tmp
;
5144 if (!OV_pop_s(vname
))
5147 tmp
= opvar_var_defined(coder
, OV_s(vname
));
5148 if (!tmp
|| (tmp
->array_len
< 1)) {
5152 for (i
= tmp
->array_len
- 1; i
> 0; i
--) {
5153 if ((j
= rn2(i
+ 1)) == i
)
5155 tmp2
= tmp
->data
.arrayvalues
[j
];
5156 tmp
->data
.arrayvalues
[j
] = tmp
->data
.arrayvalues
[i
];
5157 tmp
->data
.arrayvalues
[i
] = tmp2
;
5163 /* Special level coder, creates the special level from the sp_lev codes.
5164 * Does not free the allocated memory.
5170 static const char nhFunc
[] = "sp_level_coder";
5171 unsigned long exec_opcodes
= 0;
5173 long room_stack
= 0;
5174 unsigned long max_execution
= SPCODER_MAX_RUNTIME
;
5175 struct sp_coder
*coder
=
5176 (struct sp_coder
*) alloc(sizeof(struct sp_coder
));
5178 coder
->frame
= frame_new(0);
5179 coder
->stack
= NULL
;
5180 coder
->premapped
= FALSE
;
5181 coder
->solidify
= FALSE
;
5182 coder
->check_inaccessibles
= FALSE
;
5183 coder
->croom
= NULL
;
5184 coder
->n_subroom
= 1;
5185 coder
->exit_script
= FALSE
;
5186 coder
->lvl_is_joined
= 0;
5188 splev_init_present
= FALSE
;
5192 char *met
= nh_getenv("SPCODER_MAX_RUNTIME");
5193 if (met
&& met
[0] == '1')
5194 max_execution
= (1 << 30) - 1;
5197 for (tmpi
= 0; tmpi
<= MAX_NESTED_ROOMS
; tmpi
++) {
5198 coder
->tmproomlist
[tmpi
] = (struct mkroom
*) 0;
5199 coder
->failed_room
[tmpi
] = FALSE
;
5202 shuffle_alignments();
5204 for (tmpi
= 0; tmpi
< MAX_CONTAINMENT
; tmpi
++)
5205 container_obj
[tmpi
] = NULL
;
5208 invent_carrying_monster
= NULL
;
5210 (void) memset((genericptr_t
) &SpLev_Map
[0][0], 0, sizeof SpLev_Map
);
5212 level
.flags
.is_maze_lev
= 0;
5219 while (coder
->frame
->n_opcode
< lvl
->n_opcodes
&& !coder
->exit_script
) {
5220 coder
->opcode
= lvl
->opcodes
[coder
->frame
->n_opcode
].opcode
;
5221 coder
->opdat
= lvl
->opcodes
[coder
->frame
->n_opcode
].opdat
;
5223 coder
->stack
= coder
->frame
->stack
;
5225 if (exec_opcodes
++ > max_execution
) {
5226 impossible("Level script is taking too much time, stopping.");
5227 coder
->exit_script
= TRUE
;
5230 if (coder
->failed_room
[coder
->n_subroom
- 1]
5231 && coder
->opcode
!= SPO_ENDROOM
&& coder
->opcode
!= SPO_ROOM
5232 && coder
->opcode
!= SPO_SUBROOM
)
5235 coder
->croom
= coder
->tmproomlist
[coder
->n_subroom
- 1];
5237 switch (coder
->opcode
) {
5241 coder
->exit_script
= TRUE
;
5243 case SPO_FRAME_PUSH
:
5244 spo_frame_push(coder
);
5247 spo_frame_pop(coder
);
5255 case SPO_END_MONINVENT
:
5256 spo_end_moninvent(coder
);
5258 case SPO_POP_CONTAINER
:
5259 spo_pop_container(coder
);
5262 struct opvar
*ov
= splev_stack_pop(coder
->stack
);
5268 splev_stack_push(coder
->stack
, opvar_clone(coder
->opdat
));
5279 case SPO_LEVEL_FLAGS
:
5280 spo_level_flags(coder
);
5283 spo_initlevel(coder
);
5286 spo_engraving(coder
);
5288 case SPO_MINERALIZE
:
5289 spo_mineralize(coder
);
5293 if (!coder
->failed_room
[coder
->n_subroom
- 1]) {
5299 if (coder
->failed_room
[coder
->n_subroom
- 1]) {
5335 spo_corridor(coder
);
5340 case SPO_REPLACETERRAIN
:
5341 spo_replace_terrain(coder
);
5344 spo_levregion(coder
);
5349 case SPO_DRAWBRIDGE
:
5350 spo_drawbridge(coder
);
5353 spo_mazewalk(coder
);
5355 case SPO_NON_PASSWALL
:
5356 case SPO_NON_DIGGABLE
:
5357 spo_wall_property(coder
);
5360 spo_room_door(coder
);
5366 struct opvar
*a
= splev_stack_pop(coder
->stack
);
5368 splev_stack_push(coder
->stack
, opvar_clone(a
));
5369 splev_stack_push(coder
->stack
, opvar_clone(a
));
5379 splev_stack_push(coder
->stack
, a
);
5388 splev_stack_push(coder
->stack
, a
);
5391 case SPO_MATH_SIGN
: {
5396 OV_i(a
) = ((OV_i(a
) < 0) ? -1 : ((OV_i(a
) > 0) ? 1 : 0));
5397 splev_stack_push(coder
->stack
, a
);
5400 case SPO_MATH_ADD
: {
5401 struct opvar
*a
, *b
;
5403 if (!OV_pop(b
) || !OV_pop(a
))
5405 if (OV_typ(b
) == OV_typ(a
)) {
5406 if (OV_typ(a
) == SPOVAR_INT
) {
5407 OV_i(a
) = OV_i(a
) + OV_i(b
);
5408 splev_stack_push(coder
->stack
, a
);
5410 } else if (OV_typ(a
) == SPOVAR_STRING
) {
5412 char *tmpbuf
= (char *) alloc(strlen(OV_s(a
))
5413 + strlen(OV_s(b
)) + 1);
5415 (void) sprintf(tmpbuf
, "%s%s", OV_s(a
), OV_s(b
));
5416 c
= opvar_new_str(tmpbuf
);
5417 splev_stack_push(coder
->stack
, c
);
5422 splev_stack_push(coder
->stack
, a
);
5424 impossible("adding weird types");
5427 splev_stack_push(coder
->stack
, a
);
5429 impossible("adding different types");
5433 case SPO_MATH_SUB
: {
5434 struct opvar
*a
, *b
;
5436 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5438 OV_i(a
) = OV_i(a
) - OV_i(b
);
5439 splev_stack_push(coder
->stack
, a
);
5443 case SPO_MATH_MUL
: {
5444 struct opvar
*a
, *b
;
5446 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5448 OV_i(a
) = OV_i(a
) * OV_i(b
);
5449 splev_stack_push(coder
->stack
, a
);
5453 case SPO_MATH_DIV
: {
5454 struct opvar
*a
, *b
;
5456 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5459 OV_i(a
) = OV_i(a
) / OV_i(b
);
5463 splev_stack_push(coder
->stack
, a
);
5467 case SPO_MATH_MOD
: {
5468 struct opvar
*a
, *b
;
5470 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5473 OV_i(a
) = OV_i(a
) % OV_i(b
);
5477 splev_stack_push(coder
->stack
, a
);
5490 impossible("spo_cmp: no values in stack");
5493 if (OV_typ(a
) != OV_typ(b
)) {
5494 impossible("spo_cmp: trying to compare differing datatypes");
5497 switch (OV_typ(a
)) {
5500 case SPOVAR_MAPCHAR
:
5504 if (OV_i(b
) > OV_i(a
))
5505 val
|= SP_CPUFLAG_LT
;
5506 if (OV_i(b
) < OV_i(a
))
5507 val
|= SP_CPUFLAG_GT
;
5508 if (OV_i(b
) == OV_i(a
))
5509 val
|= SP_CPUFLAG_EQ
;
5510 c
= opvar_new_int(val
);
5513 c
= opvar_new_int(!strcmp(OV_s(b
), OV_s(a
))
5518 c
= opvar_new_int(0);
5521 splev_stack_push(coder
->stack
, c
);
5527 spo_jmp(coder
, lvl
);
5535 spo_conditional_jump(coder
, lvl
);
5541 if (!OV_pop_i(tmpv
))
5543 t
= opvar_new_int((OV_i(tmpv
) > 1) ? rn2(OV_i(tmpv
)) : 0);
5544 splev_stack_push(coder
->stack
, t
);
5549 struct opvar
*a
, *b
, *t
;
5551 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5557 t
= opvar_new_int(d(OV_i(a
), OV_i(b
)));
5558 splev_stack_push(coder
->stack
, t
);
5567 spo_var_init(coder
);
5569 case SPO_SHUFFLE_ARRAY
:
5570 spo_shuffle_array(coder
);
5572 case SPO_SEL_ADD
: /* actually, logical or */
5574 struct opvar
*sel1
, *sel2
, *pt
;
5576 if (!OV_pop_typ(sel1
, SPOVAR_SEL
))
5577 panic("no sel1 for add");
5578 if (!OV_pop_typ(sel2
, SPOVAR_SEL
))
5579 panic("no sel2 for add");
5580 pt
= selection_logical_oper(sel1
, sel2
, '|');
5583 splev_stack_push(coder
->stack
, pt
);
5586 case SPO_SEL_COMPLEMENT
: {
5587 struct opvar
*sel
, *pt
;
5589 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
5590 panic("no sel for not");
5591 pt
= selection_not(sel
);
5593 splev_stack_push(coder
->stack
, pt
);
5596 case SPO_SEL_FILTER
: /* sorta like logical and */
5598 struct opvar
*filtertype
;
5600 if (!OV_pop_i(filtertype
))
5601 panic("no sel filter type");
5602 switch (OV_i(filtertype
)) {
5603 case SPOFILTER_PERCENT
: {
5604 struct opvar
*tmp1
, *sel
;
5606 if (!OV_pop_i(tmp1
))
5607 panic("no sel filter percent");
5608 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
5609 panic("no sel filter");
5610 selection_filter_percent(sel
, OV_i(tmp1
));
5611 splev_stack_push(coder
->stack
, sel
);
5615 case SPOFILTER_SELECTION
: /* logical and */
5617 struct opvar
*pt
, *sel1
, *sel2
;
5619 if (!OV_pop_typ(sel1
, SPOVAR_SEL
))
5620 panic("no sel filter sel1");
5621 if (!OV_pop_typ(sel2
, SPOVAR_SEL
))
5622 panic("no sel filter sel2");
5623 pt
= selection_logical_oper(sel1
, sel2
, '&');
5624 splev_stack_push(coder
->stack
, pt
);
5629 case SPOFILTER_MAPCHAR
: {
5630 struct opvar
*pt
, *tmp1
, *sel
;
5632 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
5633 panic("no sel filter");
5634 if (!OV_pop_typ(tmp1
, SPOVAR_MAPCHAR
))
5635 panic("no sel filter mapchar");
5636 pt
= selection_filter_mapchar(sel
, tmp1
);
5637 splev_stack_push(coder
->stack
, pt
);
5643 panic("unknown sel filter type");
5645 opvar_free(filtertype
);
5648 case SPO_SEL_POINT
: {
5650 struct opvar
*pt
= selection_opvar((char *) 0);
5654 panic("no ter sel coord");
5655 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5656 selection_setpoint(x
, y
, pt
, 1);
5657 splev_stack_push(coder
->stack
, pt
);
5662 case SPO_SEL_FILLRECT
: {
5663 struct opvar
*tmp
, *pt
= selection_opvar((char *) 0);
5664 schar x
, y
, x1
, y1
, x2
, y2
;
5667 panic("no ter sel region");
5668 x1
= min(SP_REGION_X1(OV_i(tmp
)), SP_REGION_X2(OV_i(tmp
)));
5669 y1
= min(SP_REGION_Y1(OV_i(tmp
)), SP_REGION_Y2(OV_i(tmp
)));
5670 x2
= max(SP_REGION_X1(OV_i(tmp
)), SP_REGION_X2(OV_i(tmp
)));
5671 y2
= max(SP_REGION_Y1(OV_i(tmp
)), SP_REGION_Y2(OV_i(tmp
)));
5672 get_location(&x1
, &y1
, ANY_LOC
, coder
->croom
);
5673 get_location(&x2
, &y2
, ANY_LOC
, coder
->croom
);
5674 x1
= (x1
< 0) ? 0 : x1
;
5675 y1
= (y1
< 0) ? 0 : y1
;
5676 x2
= (x2
>= COLNO
) ? COLNO
- 1 : x2
;
5677 y2
= (y2
>= ROWNO
) ? ROWNO
- 1 : y2
;
5678 if (coder
->opcode
== SPO_SEL_RECT
) {
5679 for (x
= x1
; x
<= x2
; x
++) {
5680 selection_setpoint(x
, y1
, pt
, 1);
5681 selection_setpoint(x
, y2
, pt
, 1);
5683 for (y
= y1
; y
<= y2
; y
++) {
5684 selection_setpoint(x1
, y
, pt
, 1);
5685 selection_setpoint(x2
, y
, pt
, 1);
5688 for (x
= x1
; x
<= x2
; x
++)
5689 for (y
= y1
; y
<= y2
; y
++)
5690 selection_setpoint(x
, y
, pt
, 1);
5692 splev_stack_push(coder
->stack
, pt
);
5696 case SPO_SEL_LINE
: {
5697 struct opvar
*tmp
= NULL
, *tmp2
= NULL
,
5698 *pt
= selection_opvar((char *) 0);
5699 schar x1
, y1
, x2
, y2
;
5702 panic("no ter sel linecoord1");
5703 if (!OV_pop_c(tmp2
))
5704 panic("no ter sel linecoord2");
5705 get_location_coord(&x1
, &y1
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5706 get_location_coord(&x2
, &y2
, ANY_LOC
, coder
->croom
, OV_i(tmp2
));
5707 x1
= (x1
< 0) ? 0 : x1
;
5708 y1
= (y1
< 0) ? 0 : y1
;
5709 x2
= (x2
>= COLNO
) ? COLNO
- 1 : x2
;
5710 y2
= (y2
>= ROWNO
) ? ROWNO
- 1 : y2
;
5711 selection_do_line(x1
, y1
, x2
, y2
, pt
);
5712 splev_stack_push(coder
->stack
, pt
);
5717 case SPO_SEL_RNDLINE
: {
5718 struct opvar
*tmp
= NULL
, *tmp2
= NULL
, *tmp3
,
5719 *pt
= selection_opvar((char *) 0);
5720 schar x1
, y1
, x2
, y2
;
5722 if (!OV_pop_i(tmp3
))
5723 panic("no ter sel randline1");
5725 panic("no ter sel randline2");
5726 if (!OV_pop_c(tmp2
))
5727 panic("no ter sel randline3");
5728 get_location_coord(&x1
, &y1
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5729 get_location_coord(&x2
, &y2
, ANY_LOC
, coder
->croom
, OV_i(tmp2
));
5730 x1
= (x1
< 0) ? 0 : x1
;
5731 y1
= (y1
< 0) ? 0 : y1
;
5732 x2
= (x2
>= COLNO
) ? COLNO
- 1 : x2
;
5733 y2
= (y2
>= ROWNO
) ? ROWNO
- 1 : y2
;
5734 selection_do_randline(x1
, y1
, x2
, y2
, OV_i(tmp3
), 12, pt
);
5735 splev_stack_push(coder
->stack
, pt
);
5741 case SPO_SEL_GROW
: {
5742 struct opvar
*dirs
, *pt
;
5744 if (!OV_pop_i(dirs
))
5745 panic("no dirs for grow");
5746 if (!OV_pop_typ(pt
, SPOVAR_SEL
))
5747 panic("no selection for grow");
5748 selection_do_grow(pt
, OV_i(dirs
));
5749 splev_stack_push(coder
->stack
, pt
);
5753 case SPO_SEL_FLOOD
: {
5758 panic("no ter sel flood coord");
5759 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5761 struct opvar
*pt
= selection_opvar((char *) 0);
5763 set_selection_floodfillchk(floodfillchk_match_under
);
5764 floodfillchk_match_under_typ
= levl
[x
][y
].typ
;
5765 selection_floodfill(pt
, x
, y
, FALSE
);
5766 splev_stack_push(coder
->stack
, pt
);
5771 case SPO_SEL_RNDCOORD
: {
5775 if (!OV_pop_typ(pt
, SPOVAR_SEL
))
5776 panic("no selection for rndcoord");
5777 if (selection_rndcoord(pt
, &x
, &y
, FALSE
)) {
5781 splev_stack_push(coder
->stack
, opvar_new_coord(x
, y
));
5785 case SPO_SEL_ELLIPSE
: {
5786 struct opvar
*filled
, *xaxis
, *yaxis
, *pt
;
5787 struct opvar
*sel
= selection_opvar((char *) 0);
5790 if (!OV_pop_i(filled
))
5791 panic("no filled for ellipse");
5792 if (!OV_pop_i(yaxis
))
5793 panic("no yaxis for ellipse");
5794 if (!OV_pop_i(xaxis
))
5795 panic("no xaxis for ellipse");
5797 panic("no pt for ellipse");
5798 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(pt
));
5799 selection_do_ellipse(sel
, x
, y
, OV_i(xaxis
), OV_i(yaxis
),
5801 splev_stack_push(coder
->stack
, sel
);
5808 case SPO_SEL_GRADIENT
: {
5809 struct opvar
*gtyp
, *glim
, *mind
, *maxd
, *gcoord
, *coord2
;
5813 if (!OV_pop_i(gtyp
))
5814 panic("no gtyp for grad");
5815 if (!OV_pop_i(glim
))
5816 panic("no glim for grad");
5817 if (!OV_pop_c(coord2
))
5818 panic("no coord2 for grad");
5819 if (!OV_pop_c(gcoord
))
5820 panic("no coord for grad");
5821 if (!OV_pop_i(maxd
))
5822 panic("no maxd for grad");
5823 if (!OV_pop_i(mind
))
5824 panic("no mind for grad");
5825 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(gcoord
));
5826 get_location_coord(&x2
, &y2
, ANY_LOC
, coder
->croom
, OV_i(coord2
));
5828 sel
= selection_opvar((char *) 0);
5829 selection_do_gradient(sel
, x
, y
, x2
, y2
, OV_i(gtyp
), OV_i(mind
),
5830 OV_i(maxd
), OV_i(glim
));
5831 splev_stack_push(coder
->stack
, sel
);
5842 panic("sp_level_coder: Unknown opcode %i", coder
->opcode
);
5846 coder
->frame
->n_opcode
++;
5851 remove_boundary_syms();
5853 if (coder
->check_inaccessibles
)
5855 /* FIXME: Ideally, we want this call to only cover areas of the map
5856 * which were not inserted directly by the special level file (see
5857 * the insect legs on Baalzebub's level, for instance). Since that
5858 * is currently not possible, we overload the corrmaze flag for this
5861 if (!level
.flags
.corrmaze
)
5862 wallification(1, 0, COLNO
- 1, ROWNO
- 1);
5866 if (coder
->solidify
)
5869 /* This must be done before sokoban_detect(),
5870 * otherwise branch stairs won't be premapped. */
5873 if (coder
->premapped
)
5877 struct sp_frame
*tmpframe
;
5879 tmpframe
= coder
->frame
->next
;
5880 frame_del(coder
->frame
);
5881 coder
->frame
= tmpframe
;
5882 } while (coder
->frame
);
5898 boolean result
= FALSE
;
5899 struct version_info vers_info
;
5901 fd
= dlb_fopen(name
, RDBMODE
);
5904 Fread((genericptr_t
) &vers_info
, sizeof vers_info
, 1, fd
);
5905 if (!check_version(&vers_info
, name
, TRUE
)) {
5906 (void) dlb_fclose(fd
);
5909 lvl
= (sp_lev
*) alloc(sizeof(sp_lev
));
5910 result
= sp_level_loader(fd
, lvl
);
5911 (void) dlb_fclose(fd
);
5913 result
= sp_level_coder(lvl
);
5922 #pragma warning(pop)