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
int FDECL(pm_to_humidity
, (struct permonst
*));
76 STATIC_DCL
void FDECL(create_monster
, (monster
*, struct mkroom
*));
77 STATIC_DCL
void FDECL(create_object
, (object
*, struct mkroom
*));
78 STATIC_DCL
void FDECL(create_altar
, (altar
*, struct mkroom
*));
79 STATIC_DCL
void FDECL(replace_terrain
, (replaceterrain
*, struct mkroom
*));
80 STATIC_DCL boolean
FDECL(search_door
, (struct mkroom
*,
81 xchar
*, xchar
*, XCHAR_P
, int));
82 STATIC_DCL
void NDECL(fix_stair_rooms
);
83 STATIC_DCL
void FDECL(create_corridor
, (corridor
*));
84 STATIC_DCL
struct mkroom
*FDECL(build_room
, (room
*, struct mkroom
*));
85 STATIC_DCL
void FDECL(light_region
, (region
*));
86 STATIC_DCL
void FDECL(wallify_map
, (int, int, int, int));
87 STATIC_DCL
void FDECL(maze1xy
, (coord
*, int));
88 STATIC_DCL
void NDECL(fill_empty_maze
);
89 STATIC_DCL boolean
FDECL(sp_level_loader
, (dlb
*, sp_lev
*));
90 STATIC_DCL boolean
FDECL(sp_level_free
, (sp_lev
*));
91 STATIC_DCL
void FDECL(splev_initlev
, (lev_init
*));
92 STATIC_DCL
struct sp_frame
*FDECL(frame_new
, (long));
93 STATIC_DCL
void FDECL(frame_del
, (struct sp_frame
*));
94 STATIC_DCL
void FDECL(spo_frame_push
, (struct sp_coder
*));
95 STATIC_DCL
void FDECL(spo_frame_pop
, (struct sp_coder
*));
96 STATIC_DCL
long FDECL(sp_code_jmpaddr
, (long, long));
97 STATIC_DCL
void FDECL(spo_call
, (struct sp_coder
*));
98 STATIC_DCL
void FDECL(spo_return
, (struct sp_coder
*));
99 STATIC_DCL
void FDECL(spo_end_moninvent
, (struct sp_coder
*));
100 STATIC_DCL
void FDECL(spo_pop_container
, (struct sp_coder
*));
101 STATIC_DCL
void FDECL(spo_message
, (struct sp_coder
*));
102 STATIC_DCL
void FDECL(spo_monster
, (struct sp_coder
*));
103 STATIC_DCL
void FDECL(spo_object
, (struct sp_coder
*));
104 STATIC_DCL
void FDECL(spo_level_flags
, (struct sp_coder
*));
105 STATIC_DCL
void FDECL(spo_initlevel
, (struct sp_coder
*));
106 STATIC_DCL
void FDECL(spo_engraving
, (struct sp_coder
*));
107 STATIC_DCL
void FDECL(spo_mineralize
, (struct sp_coder
*));
108 STATIC_DCL
void FDECL(spo_room
, (struct sp_coder
*));
109 STATIC_DCL
void FDECL(spo_endroom
, (struct sp_coder
*));
110 STATIC_DCL
void FDECL(spo_stair
, (struct sp_coder
*));
111 STATIC_DCL
void FDECL(spo_ladder
, (struct sp_coder
*));
112 STATIC_DCL
void FDECL(spo_grave
, (struct sp_coder
*));
113 STATIC_DCL
void FDECL(spo_altar
, (struct sp_coder
*));
114 STATIC_DCL
void FDECL(spo_trap
, (struct sp_coder
*));
115 STATIC_DCL
void FDECL(spo_gold
, (struct sp_coder
*));
116 STATIC_DCL
void FDECL(spo_corridor
, (struct sp_coder
*));
117 STATIC_DCL
struct opvar
*FDECL(selection_opvar
, (char *));
118 STATIC_DCL xchar
FDECL(selection_getpoint
, (int, int, struct opvar
*));
119 STATIC_DCL
void FDECL(selection_setpoint
, (int, int, struct opvar
*, XCHAR_P
));
120 STATIC_DCL
struct opvar
*FDECL(selection_not
, (struct opvar
*));
121 STATIC_DCL
struct opvar
*FDECL(selection_logical_oper
, (struct opvar
*,
122 struct opvar
*, CHAR_P
));
123 STATIC_DCL
struct opvar
*FDECL(selection_filter_mapchar
, (struct opvar
*,
125 STATIC_DCL
void FDECL(selection_filter_percent
, (struct opvar
*, int));
126 STATIC_DCL
int FDECL(selection_rndcoord
, (struct opvar
*, schar
*, schar
*,
128 STATIC_DCL
void FDECL(selection_do_grow
, (struct opvar
*, int));
129 STATIC_DCL
void FDECL(set_selection_floodfillchk
, (int FDECL((*), (int,int))));
130 STATIC_DCL
int FDECL(floodfillchk_match_under
, (int, int));
131 STATIC_DCL
int FDECL(floodfillchk_match_accessible
, (int, int));
132 STATIC_DCL
void FDECL(selection_floodfill
, (struct opvar
*, int, int,
134 STATIC_DCL
void FDECL(selection_do_ellipse
, (struct opvar
*, int, int,
136 STATIC_DCL
long FDECL(line_dist_coord
, (long, long, long, long, long, long));
137 STATIC_DCL
void FDECL(selection_do_gradient
, (struct opvar
*, long, long, long,
138 long, long, long, long, long));
139 STATIC_DCL
void FDECL(selection_do_line
, (SCHAR_P
, SCHAR_P
, SCHAR_P
, SCHAR_P
,
141 STATIC_DCL
void FDECL(selection_do_randline
, (SCHAR_P
, SCHAR_P
, SCHAR_P
,
142 SCHAR_P
, SCHAR_P
, SCHAR_P
,
144 STATIC_DCL
void FDECL(selection_iterate
, (struct opvar
*, select_iter_func
,
146 STATIC_DCL
void FDECL(sel_set_ter
, (int, int, genericptr_t
));
147 STATIC_DCL
void FDECL(sel_set_feature
, (int, int, genericptr_t
));
148 STATIC_DCL
void FDECL(sel_set_door
, (int, int, genericptr_t
));
149 STATIC_DCL
void FDECL(spo_door
, (struct sp_coder
*));
150 STATIC_DCL
void FDECL(spo_feature
, (struct sp_coder
*));
151 STATIC_DCL
void FDECL(spo_terrain
, (struct sp_coder
*));
152 STATIC_DCL
void FDECL(spo_replace_terrain
, (struct sp_coder
*));
153 STATIC_DCL boolean
FDECL(generate_way_out_method
, (int, int, struct opvar
*));
154 STATIC_DCL
void NDECL(ensure_way_out
);
155 STATIC_DCL
void FDECL(spo_levregion
, (struct sp_coder
*));
156 STATIC_DCL
void FDECL(spo_region
, (struct sp_coder
*));
157 STATIC_DCL
void FDECL(spo_drawbridge
, (struct sp_coder
*));
158 STATIC_DCL
void FDECL(spo_mazewalk
, (struct sp_coder
*));
159 STATIC_DCL
void FDECL(spo_wall_property
, (struct sp_coder
*));
160 STATIC_DCL
void FDECL(spo_room_door
, (struct sp_coder
*));
161 STATIC_DCL
void FDECL(sel_set_wallify
, (int, int, genericptr_t
));
162 STATIC_DCL
void FDECL(spo_wallify
, (struct sp_coder
*));
163 STATIC_DCL
void FDECL(spo_map
, (struct sp_coder
*));
164 STATIC_DCL
void FDECL(spo_jmp
, (struct sp_coder
*, sp_lev
*));
165 STATIC_DCL
void FDECL(spo_conditional_jump
, (struct sp_coder
*, sp_lev
*));
166 STATIC_DCL
void FDECL(spo_var_init
, (struct sp_coder
*));
168 STATIC_DCL
long FDECL(opvar_array_length
, (struct sp_coder
*));
170 STATIC_DCL
void FDECL(spo_shuffle_array
, (struct sp_coder
*));
171 STATIC_DCL boolean
FDECL(sp_level_coder
, (sp_lev
*));
182 #define sq(x) ((x) * (x))
187 #define Fread (void) dlb_fread
188 #define Fgetc (schar) dlb_fgetc
189 #define New(type) (type *) alloc(sizeof(type))
190 #define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned) size)
191 #define Free(ptr) if (ptr) free((genericptr_t) (ptr))
193 extern struct engr
*head_engr
;
195 extern int min_rx
, max_rx
, min_ry
, max_ry
; /* from mkmap.c */
197 /* positions touched by level elements explicitly defined in the des-file */
198 static char SpLev_Map
[COLNO
][ROWNO
];
200 static aligntyp ralign
[3] = { AM_CHAOTIC
, AM_NEUTRAL
, AM_LAWFUL
};
201 static NEARDATA xchar xstart
, ystart
;
202 static NEARDATA
char xsize
, ysize
;
204 char *lev_message
= 0;
205 lev_region
*lregions
= 0;
206 int num_lregions
= 0;
207 boolean splev_init_present
= FALSE
;
208 boolean icedpools
= FALSE
;
210 struct obj
*container_obj
[MAX_CONTAINMENT
];
211 int container_idx
= 0;
213 struct monst
*invent_carrying_monster
= NULL
;
215 #define SPLEV_STACK_RESERVE 128
222 for (x
= 0; x
< COLNO
; x
++)
223 for (y
= 0; y
< ROWNO
; y
++)
224 if (IS_STWALL(levl
[x
][y
].typ
) && !SpLev_Map
[x
][y
])
225 levl
[x
][y
].wall_info
|= (W_NONDIGGABLE
| W_NONPASSWALL
);
230 struct splevstack
*st
;
234 st
->depth_alloc
= SPLEV_STACK_RESERVE
;
236 (struct opvar
**) alloc(st
->depth_alloc
* sizeof(struct opvar
*));
242 struct splevstack
*st
;
247 if (st
->stackdata
&& st
->depth
) {
248 for (i
= 0; i
< st
->depth
; i
++) {
249 switch (st
->stackdata
[i
]->spovartyp
) {
259 case SPOVAR_VARIABLE
:
262 Free(st
->stackdata
[i
]->vardata
.str
);
263 st
->stackdata
[i
]->vardata
.str
= NULL
;
266 Free(st
->stackdata
[i
]);
267 st
->stackdata
[i
] = NULL
;
271 st
->stackdata
= NULL
;
272 st
->depth
= st
->depth_alloc
= 0;
278 splev_stack_push(st
, v
)
279 struct splevstack
*st
;
285 panic("splev_stack_push: no stackdata allocated?");
287 if (st
->depth
>= st
->depth_alloc
) {
288 struct opvar
**tmp
= (struct opvar
**) alloc(
289 (st
->depth_alloc
+ SPLEV_STACK_RESERVE
) * sizeof(struct opvar
*));
291 (void) memcpy(tmp
, st
->stackdata
,
292 st
->depth_alloc
* sizeof(struct opvar
*));
295 st
->depth_alloc
+= SPLEV_STACK_RESERVE
;
298 st
->stackdata
[st
->depth
] = v
;
304 struct splevstack
*st
;
306 struct opvar
*ret
= NULL
;
311 panic("splev_stack_pop: no stackdata allocated?");
315 ret
= st
->stackdata
[st
->depth
];
316 st
->stackdata
[st
->depth
] = NULL
;
319 impossible("splev_stack_pop: empty stack?");
324 splev_stack_reverse(st
)
325 struct splevstack
*st
;
333 panic("splev_stack_reverse: no stackdata allocated?");
334 for (i
= 0; i
< (st
->depth
/ 2); i
++) {
335 tmp
= st
->stackdata
[i
];
336 st
->stackdata
[i
] = st
->stackdata
[st
->depth
- i
- 1];
337 st
->stackdata
[st
->depth
- i
- 1] = tmp
;
342 #define OV_typ(o) (o->spovartyp)
343 #define OV_i(o) (o->vardata.l)
344 #define OV_s(o) (o->vardata.str)
346 #define OV_pop_i(x) (x = splev_stack_getdat(coder, SPOVAR_INT))
347 #define OV_pop_c(x) (x = splev_stack_getdat(coder, SPOVAR_COORD))
348 #define OV_pop_r(x) (x = splev_stack_getdat(coder, SPOVAR_REGION))
349 #define OV_pop_s(x) (x = splev_stack_getdat(coder, SPOVAR_STRING))
350 #define OV_pop(x) (x = splev_stack_getdat_any(coder))
351 #define OV_pop_typ(x, typ) (x = splev_stack_getdat(coder, typ))
357 struct opvar
*tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
359 tmpov
->spovartyp
= SPOVAR_STRING
;
362 tmpov
->vardata
.str
= (char *) alloc(len
+ 1);
363 (void) memcpy((genericptr_t
) tmpov
->vardata
.str
, (genericptr_t
) s
,
365 tmpov
->vardata
.str
[len
] = '\0';
367 tmpov
->vardata
.str
= NULL
;
375 struct opvar
*tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
377 tmpov
->spovartyp
= SPOVAR_INT
;
378 tmpov
->vardata
.l
= i
;
383 opvar_new_coord(x
, y
)
386 struct opvar
*tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
388 tmpov
->spovartyp
= SPOVAR_COORD
;
389 tmpov
->vardata
.l
= SP_COORD_PACK(x
, y
);
395 opvar_new_region(x1
,y1
,x2
,y2
)
398 struct opvar
*tmpov
= (struct opvar
*)alloc(sizeof (struct opvar
));
400 tmpov
->spovartyp
= SPOVAR_REGION
;
401 tmpov
->vardata
.l
= SP_REGION_PACK(x1
,y1
,x2
,y2
);
412 switch (ov
->spovartyp
) {
420 case SPOVAR_VARIABLE
:
423 Free(ov
->vardata
.str
);
426 impossible("Unknown opvar value type (%i)!", ov
->spovartyp
);
432 * Name of current function for use in messages:
433 * __func__ -- C99 standard;
434 * __FUNCTION__ -- gcc extension, starting before C99 and continuing after;
435 * picked up by other compilers (or vice versa?);
436 * __FUNC__ -- supported by Borland;
437 * nhFunc -- slightly intrusive but fully portable nethack construct
438 * for any version of any compiler.
440 #define opvar_free(ov) \
446 impossible("opvar_free(), %s", nhFunc); \
456 panic("no opvar to clone");
457 tmpov
= (struct opvar
*) alloc(sizeof(struct opvar
));
458 tmpov
->spovartyp
= ov
->spovartyp
;
459 switch (ov
->spovartyp
) {
466 tmpov
->vardata
.l
= ov
->vardata
.l
;
468 case SPOVAR_VARIABLE
:
471 tmpov
->vardata
.str
= dupstr(ov
->vardata
.str
);
474 impossible("Unknown push value type (%i)!", ov
->spovartyp
);
480 opvar_var_conversion(coder
, ov
)
481 struct sp_coder
*coder
;
484 static const char nhFunc
[] = "opvar_var_conversion";
485 struct splev_var
*tmp
;
487 struct opvar
*array_idx
= NULL
;
491 if (ov
->spovartyp
!= SPOVAR_VARIABLE
)
493 tmp
= coder
->frame
->variables
;
495 if (!strcmp(tmp
->name
, OV_s(ov
))) {
496 if ((tmp
->svtyp
& SPOVAR_ARRAY
)) {
497 array_idx
= opvar_var_conversion(coder
,
498 splev_stack_pop(coder
->stack
));
499 if (!array_idx
|| OV_typ(array_idx
) != SPOVAR_INT
)
500 panic("array idx not an int");
501 if (tmp
->array_len
< 1)
502 panic("array len < 1");
503 OV_i(array_idx
) = (OV_i(array_idx
) % tmp
->array_len
);
504 tmpov
= opvar_clone(tmp
->data
.arrayvalues
[OV_i(array_idx
)]);
505 opvar_free(array_idx
);
508 tmpov
= opvar_clone(tmp
->data
.value
);
518 opvar_var_defined(coder
, name
)
519 struct sp_coder
*coder
;
522 struct splev_var
*tmp
;
526 tmp
= coder
->frame
->variables
;
528 if (!strcmp(tmp
->name
, name
))
536 splev_stack_getdat(coder
, typ
)
537 struct sp_coder
*coder
;
540 static const char nhFunc
[] = "splev_stack_getdat";
541 if (coder
&& coder
->stack
) {
542 struct opvar
*tmp
= splev_stack_pop(coder
->stack
);
543 struct opvar
*ret
= NULL
;
546 panic("no value type %i in stack.", typ
);
547 if (tmp
->spovartyp
== SPOVAR_VARIABLE
) {
548 ret
= opvar_var_conversion(coder
, tmp
);
552 if (tmp
->spovartyp
== typ
)
554 else opvar_free(tmp
);
560 splev_stack_getdat_any(coder
)
561 struct sp_coder
*coder
;
563 static const char nhFunc
[] = "splev_stack_getdat_any";
564 if (coder
&& coder
->stack
) {
565 struct opvar
*tmp
= splev_stack_pop(coder
->stack
);
566 if (tmp
&& tmp
->spovartyp
== SPOVAR_VARIABLE
) {
567 struct opvar
*ret
= opvar_var_conversion(coder
, tmp
);
577 variable_list_del(varlist
)
578 struct splev_var
*varlist
;
580 static const char nhFunc
[] = "variable_list_del";
581 struct splev_var
*tmp
= varlist
;
587 if ((tmp
->svtyp
& SPOVAR_ARRAY
)) {
588 long idx
= tmp
->array_len
;
591 opvar_free(tmp
->data
.arrayvalues
[idx
]);
593 Free(tmp
->data
.arrayvalues
);
595 opvar_free(tmp
->data
.value
);
604 lvlfill_maze_grid(x1
, y1
, x2
, y2
, filling
)
610 for (x
= x1
; x
<= x2
; x
++)
611 for (y
= y1
; y
<= y2
; y
++) {
612 if (level
.flags
.corrmaze
)
613 levl
[x
][y
].typ
= STONE
;
615 levl
[x
][y
].typ
= (y
< 2 || ((x
% 2) && (y
% 2))) ? STONE
621 lvlfill_solid(filling
, lit
)
626 for (x
= 2; x
<= x_maze_max
; x
++)
627 for (y
= 0; y
<= y_maze_max
; y
++) {
628 SET_TYPLIT(x
, y
, filling
, lit
);
633 * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
636 set_wall_property(x1
, y1
, x2
, y2
, prop
)
637 xchar x1
, y1
, x2
, y2
;
642 for (y
= max(y1
, 0); y
<= min(y2
, ROWNO
- 1); y
++)
643 for (x
= max(x1
, 0); x
<= min(x2
, COLNO
- 1); x
++)
644 if (IS_STWALL(levl
[x
][y
].typ
) || IS_TREE(levl
[x
][y
].typ
))
645 levl
[x
][y
].wall_info
|= prop
;
654 /* shuffle 3 alignments */
657 ralign
[2] = ralign
[i
];
661 ralign
[1] = ralign
[0];
667 * Count the different features (sinks, fountains) in the level.
674 level
.flags
.nfountains
= level
.flags
.nsinks
= 0;
675 for (y
= 0; y
< ROWNO
; y
++)
676 for (x
= 0; x
< COLNO
; x
++) {
677 int typ
= levl
[x
][y
].typ
;
679 level
.flags
.nfountains
++;
680 else if (typ
== SINK
)
681 level
.flags
.nsinks
++;
686 remove_boundary_syms()
689 * If any CROSSWALLs are found, must change to ROOM after REGION's
690 * are laid out. CROSSWALLS are used to specify "invisible"
691 * boundaries where DOOR syms look bad or aren't desirable.
694 boolean has_bounds
= FALSE
;
696 for (x
= 0; x
< COLNO
- 1; x
++)
697 for (y
= 0; y
< ROWNO
- 1; y
++)
698 if (levl
[x
][y
].typ
== CROSSWALL
) {
703 for (x
= 0; x
< x_maze_max
; x
++)
704 for (y
= 0; y
< y_maze_max
; y
++)
705 if ((levl
[x
][y
].typ
== CROSSWALL
) && SpLev_Map
[x
][y
])
706 levl
[x
][y
].typ
= ROOM
;
711 maybe_add_door(x
, y
, droom
)
713 struct mkroom
*droom
;
715 if (droom
->hx
>= 0 && doorindex
< DOORMAX
&& inside_room(droom
, x
, y
))
716 add_door(x
, y
, droom
);
725 for (y
= 0; y
< ROWNO
; y
++)
726 for (x
= 0; x
< COLNO
; x
++)
727 if (IS_DOOR(levl
[x
][y
].typ
) || levl
[x
][y
].typ
== SDOOR
) {
728 for (tmpi
= 0; tmpi
< nroom
; tmpi
++) {
729 maybe_add_door(x
, y
, &rooms
[tmpi
]);
730 for (m
= 0; m
< rooms
[tmpi
].nsubrooms
; m
++) {
731 maybe_add_door(x
, y
, rooms
[tmpi
].sbrooms
[m
]);
742 for (tmpi
= 0; tmpi
< nroom
; tmpi
++) {
744 if (rooms
[tmpi
].needfill
)
745 fill_room(&rooms
[tmpi
], (rooms
[tmpi
].needfill
== 2));
746 for (m
= 0; m
< rooms
[tmpi
].nsubrooms
; m
++)
747 if (rooms
[tmpi
].sbrooms
[m
]->needfill
)
748 fill_room(rooms
[tmpi
].sbrooms
[m
], FALSE
);
753 * Choose randomly the state (nodoor, open, closed or locked) for a door
765 * Select a random trap
773 rtrap
= rnd(TRAPNUM
- 1);
775 case HOLE
: /* no random holes on special levels */
776 case VIBRATING_SQUARE
:
781 if (!Can_dig_down(&u
.uz
))
786 if (level
.flags
.noteleport
)
789 case ROLLING_BOULDER_TRAP
:
791 if (In_endgame(&u
.uz
))
795 } while (rtrap
== NO_TRAP
);
800 * Coordinates in special level files are handled specially:
802 * if x or y is < 0, we generate a random coordinate.
803 * The "humidity" flag is used to insure that engravings aren't
804 * created underwater, or eels on dry land.
807 get_location(x
, y
, humidity
, croom
)
810 struct mkroom
*croom
;
818 sx
= croom
->hx
- mx
+ 1;
819 sy
= croom
->hy
- my
+ 1;
827 if (*x
>= 0) { /* normal locations */
830 } else { /* random location */
832 if (croom
) { /* handle irregular areas */
834 somexy(croom
, &tmpc
);
838 *x
= mx
+ rn2((int) sx
);
839 *y
= my
+ rn2((int) sy
);
841 if (is_ok_location(*x
, *y
, humidity
))
843 } while (++cpt
< 100);
848 for (xx
= 0; xx
< sx
; xx
++)
849 for (yy
= 0; yy
< sy
; yy
++) {
852 if (is_ok_location(*x
, *y
, humidity
))
855 if (!(humidity
& NO_LOC_WARN
)) {
856 impossible("get_location: can't find a place!");
865 if (!(humidity
& ANY_LOC
) && !isok(*x
, *y
)) {
866 if (!(humidity
& NO_LOC_WARN
)) {
867 /*warning("get_location: (%d,%d) out of bounds", *x, *y);*/
877 is_ok_location(x
, y
, humidity
)
879 register int humidity
;
883 if (Is_waterlevel(&u
.uz
))
884 return TRUE
; /* accept any spot */
886 /* TODO: Should perhaps check if wall is diggable/passwall? */
887 if (humidity
& ANY_LOC
)
890 if ((humidity
& SOLID
) && IS_ROCK(levl
[x
][y
].typ
))
893 if (humidity
& DRY
) {
894 typ
= levl
[x
][y
].typ
;
895 if (typ
== ROOM
|| typ
== AIR
|| typ
== CLOUD
|| typ
== ICE
899 if ((humidity
& SPACELOC
) && SPACE_POS(levl
[x
][y
].typ
))
901 if ((humidity
& WET
) && is_pool(x
, y
))
903 if ((humidity
& HOT
) && is_lava(x
, y
))
909 get_unpacked_coord(loc
, defhumidity
)
913 static unpacked_coord c
;
915 if (loc
& SP_COORD_IS_RANDOM
) {
918 c
.getloc_flags
= (loc
& ~SP_COORD_IS_RANDOM
);
920 c
.getloc_flags
= defhumidity
;
923 c
.getloc_flags
= defhumidity
;
924 c
.x
= SP_COORD_X(loc
);
925 c
.y
= SP_COORD_Y(loc
);
931 get_location_coord(x
, y
, humidity
, croom
, crd
)
934 struct mkroom
*croom
;
939 c
= get_unpacked_coord(crd
, humidity
);
942 get_location(x
, y
, c
.getloc_flags
| (c
.is_random
? NO_LOC_WARN
: 0),
944 if (*x
== -1 && *y
== -1 && c
.is_random
)
945 get_location(x
, y
, humidity
, croom
);
949 * Get a relative position inside a room.
950 * negative values for x or y means RANDOM!
954 get_room_loc(x
, y
, croom
)
956 struct mkroom
*croom
;
960 if (*x
< 0 && *y
< 0) {
961 if (somexy(croom
, &c
)) {
965 panic("get_room_loc : can't find a place!");
968 *x
= rn2(croom
->hx
- croom
->lx
+ 1);
970 *y
= rn2(croom
->hy
- croom
->ly
+ 1);
977 * Get a relative position inside a room.
978 * negative values for x or y means RANDOM!
981 get_free_room_loc(x
, y
, croom
, pos
)
983 struct mkroom
*croom
;
987 register int trycnt
= 0;
989 get_location_coord(&try_x
, &try_y
, DRY
, croom
, pos
);
990 if (levl
[try_x
][try_y
].typ
!= ROOM
) {
992 try_x
= *x
, try_y
= *y
;
993 get_room_loc(&try_x
, &try_y
, croom
);
994 } while (levl
[try_x
][try_y
].typ
!= ROOM
&& ++trycnt
<= 100);
997 panic("get_free_room_loc: can't find a place!");
999 *x
= try_x
, *y
= try_y
;
1003 check_room(lowx
, ddx
, lowy
, ddy
, vault
)
1004 xchar
*lowx
, *ddx
, *lowy
, *ddy
;
1007 register int x
, y
, hix
= *lowx
+ *ddx
, hiy
= *lowy
+ *ddy
;
1008 register struct rm
*lev
;
1009 int xlim
, ylim
, ymax
;
1011 xlim
= XLIM
+ (vault
? 1 : 0);
1012 ylim
= YLIM
+ (vault
? 1 : 0);
1018 if (hix
> COLNO
- 3)
1020 if (hiy
> ROWNO
- 3)
1023 if (hix
<= *lowx
|| hiy
<= *lowy
)
1026 /* check area around room (and make room smaller if necessary) */
1027 for (x
= *lowx
- xlim
; x
<= hix
+ xlim
; x
++) {
1028 if (x
<= 0 || x
>= COLNO
)
1037 for (; y
<= ymax
; y
++) {
1040 debugpline2("strange area [%d,%d] in check_room.", x
, y
);
1045 *lowx
= x
+ xlim
+ 1;
1049 *lowy
= y
+ ylim
+ 1;
1062 * Create a new room.
1063 * This is still very incomplete...
1066 create_room(x
, y
, w
, h
, xal
, yal
, rtype
, rlit
)
1073 int wtmp
, htmp
, xaltmp
, yaltmp
, xtmp
, ytmp
;
1076 boolean vault
= FALSE
;
1077 int xlim
= XLIM
, ylim
= YLIM
;
1079 if (rtype
== -1) /* Is the type random ? */
1082 if (rtype
== VAULT
) {
1088 /* on low levels the room is lit (usually) */
1089 /* some other rooms may require lighting */
1091 /* is light state random ? */
1093 rlit
= (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? TRUE
: FALSE
;
1096 * Here we will try to create a room. If some parameters are
1097 * random we are willing to make several try before we give
1101 xchar xborder
, yborder
;
1109 /* First case : a totally random room */
1111 if ((xtmp
< 0 && ytmp
< 0 && wtmp
< 0 && xaltmp
< 0 && yaltmp
< 0)
1113 xchar hx
, hy
, lx
, ly
, dx
, dy
;
1114 r1
= rnd_rect(); /* Get a random rectangle */
1116 if (!r1
) { /* No more free rectangles ! */
1117 debugpline0("No more rects...");
1127 dx
= 2 + rn2((hx
- lx
> 28) ? 12 : 8);
1132 xborder
= (lx
> 0 && hx
< COLNO
- 1) ? 2 * xlim
: xlim
+ 1;
1133 yborder
= (ly
> 0 && hy
< ROWNO
- 1) ? 2 * ylim
: ylim
+ 1;
1134 if (hx
- lx
< dx
+ 3 + xborder
|| hy
- ly
< dy
+ 3 + yborder
) {
1138 xabs
= lx
+ (lx
> 0 ? xlim
: 3)
1139 + rn2(hx
- (lx
> 0 ? lx
: 3) - dx
- xborder
+ 1);
1140 yabs
= ly
+ (ly
> 0 ? ylim
: 2)
1141 + rn2(hy
- (ly
> 0 ? ly
: 2) - dy
- yborder
+ 1);
1142 if (ly
== 0 && hy
>= (ROWNO
- 1) && (!nroom
|| !rn2(nroom
))
1143 && (yabs
+ dy
> ROWNO
/ 2)) {
1145 if (nroom
< 4 && dy
> 1)
1148 if (!check_room(&xabs
, &dx
, &yabs
, &dy
, vault
)) {
1156 r2
.hx
= xabs
+ wtmp
;
1157 r2
.hy
= yabs
+ htmp
;
1158 } else { /* Only some parameters are random */
1160 if (xtmp
< 0 && ytmp
< 0) { /* Position is RANDOM */
1165 if (wtmp
< 0 || htmp
< 0) { /* Size is RANDOM */
1169 if (xaltmp
== -1) /* Horizontal alignment is RANDOM */
1171 if (yaltmp
== -1) /* Vertical alignment is RANDOM */
1174 /* Try to generate real (absolute) coordinates here! */
1176 xabs
= (((xtmp
- 1) * COLNO
) / 5) + 1;
1177 yabs
= (((ytmp
- 1) * ROWNO
) / 5) + 1;
1182 xabs
+= (COLNO
/ 5) - wtmp
;
1185 xabs
+= ((COLNO
/ 5) - wtmp
) / 2;
1192 yabs
+= (ROWNO
/ 5) - htmp
;
1195 yabs
+= ((ROWNO
/ 5) - htmp
) / 2;
1199 if (xabs
+ wtmp
- 1 > COLNO
- 2)
1200 xabs
= COLNO
- wtmp
- 3;
1203 if (yabs
+ htmp
- 1 > ROWNO
- 2)
1204 yabs
= ROWNO
- htmp
- 3;
1208 /* Try to find a rectangle that fit our room ! */
1212 r2
.hx
= xabs
+ wtmp
+ rndpos
;
1213 r2
.hy
= yabs
+ htmp
+ rndpos
;
1216 } while (++trycnt
<= 100 && !r1
);
1217 if (!r1
) { /* creation of room failed ? */
1220 split_rects(r1
, &r2
);
1223 smeq
[nroom
] = nroom
;
1224 add_room(xabs
, yabs
, xabs
+ wtmp
- 1, yabs
+ htmp
- 1, rlit
, rtype
,
1227 rooms
[nroom
].lx
= xabs
;
1228 rooms
[nroom
].ly
= yabs
;
1234 * Create a subroom in room proom at pos x,y with width w & height h.
1235 * x & y are relative to the parent room.
1238 create_subroom(proom
, x
, y
, w
, h
, rtype
, rlit
)
1239 struct mkroom
*proom
;
1244 xchar width
, height
;
1246 width
= proom
->hx
- proom
->lx
+ 1;
1247 height
= proom
->hy
- proom
->ly
+ 1;
1249 /* There is a minimum size for the parent room */
1250 if (width
< 4 || height
< 4)
1253 /* Check for random position, size, etc... */
1258 h
= rnd(height
- 3);
1260 x
= rnd(width
- w
- 1) - 1;
1262 y
= rnd(height
- h
- 1) - 1;
1267 if ((x
+ w
+ 1) == width
)
1269 if ((y
+ h
+ 1) == height
)
1274 rlit
= (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? TRUE
: FALSE
;
1275 add_subroom(proom
, proom
->lx
+ x
, proom
->ly
+ y
, proom
->lx
+ x
+ w
- 1,
1276 proom
->ly
+ y
+ h
- 1, rlit
, rtype
, FALSE
);
1281 * Create a new door in a room.
1282 * It's placed on a wall (north, south, east or west).
1285 create_door(dd
, broom
)
1287 struct mkroom
*broom
;
1290 int trycnt
= 0, wtry
= 0;
1292 if (dd
->secret
== -1)
1293 dd
->secret
= rn2(2);
1295 if (dd
->mask
== -1) {
1296 /* is it a locked door, closed, or a doorway? */
1300 dd
->mask
= D_ISOPEN
;
1302 dd
->mask
= D_LOCKED
;
1304 dd
->mask
= D_CLOSED
;
1305 if (dd
->mask
!= D_ISOPEN
&& !rn2(25))
1306 dd
->mask
|= D_TRAPPED
;
1308 dd
->mask
= D_NODOOR
;
1311 dd
->mask
= D_LOCKED
;
1313 dd
->mask
= D_CLOSED
;
1316 dd
->mask
|= D_TRAPPED
;
1321 register int dwall
, dpos
;
1324 if (dwall
== -1) /* The wall is RANDOM */
1325 dwall
= 1 << rn2(4);
1329 /* Convert wall and pos into an absolute coordinate! */
1333 if (!(dwall
& W_NORTH
))
1337 + ((dpos
== -1) ? rn2(1 + (broom
->hx
- broom
->lx
)) : dpos
);
1338 if (IS_ROCK(levl
[x
][y
- 1].typ
))
1342 if (!(dwall
& W_SOUTH
))
1346 + ((dpos
== -1) ? rn2(1 + (broom
->hx
- broom
->lx
)) : dpos
);
1347 if (IS_ROCK(levl
[x
][y
+ 1].typ
))
1351 if (!(dwall
& W_WEST
))
1355 + ((dpos
== -1) ? rn2(1 + (broom
->hy
- broom
->ly
)) : dpos
);
1356 if (IS_ROCK(levl
[x
- 1][y
].typ
))
1360 if (!(dwall
& W_EAST
))
1364 + ((dpos
== -1) ? rn2(1 + (broom
->hy
- broom
->ly
)) : dpos
);
1365 if (IS_ROCK(levl
[x
+ 1][y
].typ
))
1370 panic("create_door: No wall for door!");
1378 } while (++trycnt
<= 100);
1380 impossible("create_door: Can't find a proper place!");
1383 levl
[x
][y
].typ
= (dd
->secret
? SDOOR
: DOOR
);
1384 levl
[x
][y
].doormask
= dd
->mask
;
1388 * Create a secret door in croom on any one of the specified walls.
1391 create_secret_door(croom
, walls
)
1392 struct mkroom
*croom
;
1393 xchar walls
; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
1395 xchar sx
, sy
; /* location of the secret door */
1398 for (count
= 0; count
< 100; count
++) {
1399 sx
= rn1(croom
->hx
- croom
->lx
+ 1, croom
->lx
);
1400 sy
= rn1(croom
->hy
- croom
->ly
+ 1, croom
->ly
);
1404 if (!(walls
& W_NORTH
))
1408 case 1: /* bottom */
1409 if (!(walls
& W_SOUTH
))
1414 if (!(walls
& W_EAST
))
1419 if (!(walls
& W_WEST
))
1425 if (okdoor(sx
, sy
)) {
1426 levl
[sx
][sy
].typ
= SDOOR
;
1427 levl
[sx
][sy
].doormask
= D_CLOSED
;
1432 impossible("couldn't create secret door on any walls 0x%x", walls
);
1436 * Create a trap in a room.
1439 create_trap(t
, croom
)
1441 struct mkroom
*croom
;
1447 get_free_room_loc(&x
, &y
, croom
, t
->coord
);
1451 get_location_coord(&x
, &y
, DRY
, croom
, t
->coord
);
1452 } while ((levl
[x
][y
].typ
== STAIRS
|| levl
[x
][y
].typ
== LADDER
)
1453 && ++trycnt
<= 100);
1461 mktrap(t
->type
, 1, (struct mkroom
*) 0, &tm
);
1465 * Create a monster in a room.
1468 noncoalignment(alignment
)
1475 return (k
? -1 : 1);
1476 return (k
? -alignment
: 0);
1479 /* attempt to screen out locations where a mimic-as-boulder shouldn't occur */
1481 m_bad_boulder_spot(x
, y
)
1486 /* avoid trap locations */
1489 /* try to avoid locations which already have a boulder (this won't
1490 actually work; we get called before objects have been placed...) */
1491 if (sobj_at(BOULDER
, x
, y
))
1493 /* avoid closed doors */
1495 if (IS_DOOR(lev
->typ
) && (lev
->doormask
& (D_CLOSED
| D_LOCKED
)) != 0)
1503 struct permonst
*pm
;
1508 if (pm
->mlet
== S_EEL
|| amphibious(pm
) || is_swimmer(pm
))
1510 if (is_flyer(pm
) || is_floater(pm
))
1512 if (passes_walls(pm
) || noncorporeal(pm
))
1520 create_monster(m
, croom
)
1522 struct mkroom
*croom
;
1529 struct permonst
*pm
;
1533 class = (char) def_char_to_monclass((char) m
->class);
1537 if (class == MAXMCLASSES
)
1538 panic("create_monster: unknown monster class '%c'", m
->class);
1540 amask
= (m
->align
== AM_SPLEV_CO
)
1541 ? Align2amask(u
.ualignbase
[A_ORIGINAL
])
1542 : (m
->align
== AM_SPLEV_NONCO
)
1543 ? Align2amask(noncoalignment(u
.ualignbase
[A_ORIGINAL
]))
1544 : (m
->align
<= -(MAX_REGISTERS
+ 1))
1546 : (m
->align
< 0 ? ralign
[-m
->align
- 1] : m
->align
);
1549 pm
= (struct permonst
*) 0;
1550 else if (m
->id
!= NON_PM
) {
1552 g_mvflags
= (unsigned) mvitals
[monsndx(pm
)].mvflags
;
1553 if ((pm
->geno
& G_UNIQ
) && (g_mvflags
& G_EXTINCT
))
1555 else if (g_mvflags
& G_GONE
) /* genocided or extinct */
1556 pm
= (struct permonst
*) 0; /* make random monster */
1558 pm
= mkclass(class, G_NOGEN
);
1559 /* if we can't get a specific monster type (pm == 0) then the
1560 class has been genocided, so settle for a random monster */
1562 if (In_mines(&u
.uz
) && pm
&& your_race(pm
)
1563 && (Race_if(PM_DWARF
) || Race_if(PM_GNOME
)) && rn2(3))
1564 pm
= (struct permonst
*) 0;
1567 int loc
= pm_to_humidity(pm
);
1568 /* If water-liking monster, first try is without DRY */
1569 get_location_coord(&x
, &y
, loc
| NO_LOC_WARN
, croom
, m
->coord
);
1570 if (x
== -1 && y
== -1) {
1572 get_location_coord(&x
, &y
, loc
, croom
, m
->coord
);
1575 get_location_coord(&x
, &y
, DRY
, croom
, m
->coord
);
1578 /* try to find a close place if someone else is already there */
1579 if (MON_AT(x
, y
) && enexto(&cc
, x
, y
, pm
))
1582 if (m
->align
!= -(MAX_REGISTERS
+ 2))
1583 mtmp
= mk_roamer(pm
, Amask2align(amask
), x
, y
, m
->peaceful
);
1584 else if (PM_ARCHEOLOGIST
<= m
->id
&& m
->id
<= PM_WIZARD
)
1585 mtmp
= mk_mplayer(pm
, x
, y
, FALSE
);
1587 mtmp
= makemon(pm
, x
, y
, NO_MM_FLAGS
);
1590 x
= mtmp
->mx
, y
= mtmp
->my
; /* sanity precaution */
1592 /* handle specific attributes for some special monsters */
1594 mtmp
= christen_monst(mtmp
, m
->name
.str
);
1597 * This is currently hardwired for mimics only. It should
1598 * eventually be expanded.
1600 if (m
->appear_as
.str
1601 && ((mtmp
->data
->mlet
== S_MIMIC
) || mtmp
->cham
)
1602 && !Protection_from_shape_changers
) {
1605 switch (m
->appear
) {
1608 "create_monster: mon has an appearance, \"%s\", but no type",
1612 case M_AP_FURNITURE
:
1613 for (i
= 0; i
< MAXPCHARS
; i
++)
1614 if (!strcmp(defsyms
[i
].explanation
, m
->appear_as
.str
))
1616 if (i
== MAXPCHARS
) {
1617 impossible("create_monster: can't find feature \"%s\"",
1620 mtmp
->m_ap_type
= M_AP_FURNITURE
;
1621 mtmp
->mappearance
= i
;
1626 for (i
= 0; i
< NUM_OBJECTS
; i
++)
1627 if (OBJ_NAME(objects
[i
])
1628 && !strcmp(OBJ_NAME(objects
[i
]), m
->appear_as
.str
))
1630 if (i
== NUM_OBJECTS
) {
1631 impossible("create_monster: can't find object \"%s\"",
1634 mtmp
->m_ap_type
= M_AP_OBJECT
;
1635 mtmp
->mappearance
= i
;
1636 /* try to avoid placing mimic boulder on a trap */
1637 if (i
== BOULDER
&& m
->x
< 0
1638 && m_bad_boulder_spot(x
, y
)) {
1639 int retrylimit
= 10;
1641 remove_monster(x
, y
);
1645 get_location(&x
, &y
, DRY
, croom
);
1646 if (MON_AT(x
, y
) && enexto(&cc
, x
, y
, pm
))
1648 } while (m_bad_boulder_spot(x
, y
)
1649 && --retrylimit
> 0);
1650 place_monster(mtmp
, x
, y
);
1651 /* if we didn't find a good spot
1652 then mimic something else */
1654 set_mimic_sym(mtmp
);
1659 case M_AP_MONSTER
: {
1662 if (!strcmpi(m
->appear_as
.str
, "random"))
1663 mndx
= select_newcham_form(mtmp
);
1665 mndx
= name_to_mon(m
->appear_as
.str
);
1666 if ((mndx
!= NON_PM
) && (&mons
[mndx
] != mtmp
->data
)) {
1667 struct permonst
*mdat
= &mons
[mndx
];
1668 struct permonst
*olddata
= mtmp
->data
;
1670 mgender_from_permonst(mtmp
, mdat
);
1671 set_mon_data(mtmp
, mdat
, 0);
1672 if (emits_light(olddata
) != emits_light(mtmp
->data
)) {
1673 /* used to give light, now doesn't, or vice versa,
1674 or light's range has changed */
1675 if (emits_light(olddata
))
1676 del_light_source(LS_MONSTER
, (genericptr_t
) mtmp
);
1677 if (emits_light(mtmp
->data
))
1678 new_light_source(mtmp
->mx
, mtmp
->my
,
1679 emits_light(mtmp
->data
),
1680 LS_MONSTER
, (genericptr_t
) mtmp
);
1682 if (!mtmp
->perminvis
|| pm_invisible(olddata
))
1683 mtmp
->perminvis
= pm_invisible(mdat
);
1689 "create_monster: unimplemented mon appear type [%d,\"%s\"]",
1690 m
->appear
, m
->appear_as
.str
);
1693 if (does_block(x
, y
, &levl
[x
][y
]))
1697 if (m
->peaceful
>= 0) {
1698 mtmp
->mpeaceful
= m
->peaceful
;
1699 /* changed mpeaceful again; have to reset malign */
1702 if (m
->asleep
>= 0) {
1704 /* optimizer bug strikes again */
1706 mtmp
->msleeping
= 1;
1708 mtmp
->msleeping
= 0;
1710 mtmp
->msleeping
= m
->asleep
;
1714 mtmp
->mtrapseen
= m
->seentraps
;
1728 mtmp
->minvis
= mtmp
->perminvis
= 1;
1732 mtmp
->mblinded
= (m
->blinded
% 127);
1736 mtmp
->mfrozen
= (m
->paralyzed
% 127);
1740 mtmp
->mfleetim
= (m
->fleeing
% 127);
1743 if (m
->has_invent
) {
1744 discard_minvent(mtmp
);
1745 invent_carrying_monster
= mtmp
;
1751 * Create an object in a room.
1754 create_object(o
, croom
)
1756 struct mkroom
*croom
;
1761 boolean named
; /* has a name been supplied in level description? */
1763 named
= o
->name
.str
? TRUE
: FALSE
;
1765 get_location_coord(&x
, &y
, DRY
, croom
, o
->coord
);
1773 otmp
= mkobj_at(RANDOM_CLASS
, x
, y
, !named
);
1774 else if (o
->id
!= -1)
1775 otmp
= mksobj_at(o
->id
, x
, y
, TRUE
, !named
);
1778 * The special levels are compiled with the default "text" object
1779 * class characters. We must convert them to the internal format.
1781 char oclass
= (char) def_char_to_objclass(c
);
1783 if (oclass
== MAXOCLASSES
)
1784 panic("create_object: unexpected object class '%c'", c
);
1786 /* KMH -- Create piles of gold properly */
1787 if (oclass
== COIN_CLASS
)
1788 otmp
= mkgold(0L, x
, y
);
1790 otmp
= mkobj_at(oclass
, x
, y
, !named
);
1793 if (o
->spe
!= -127) /* That means NOT RANDOM! */
1794 otmp
->spe
= (schar
) o
->spe
;
1796 switch (o
->curse_state
) {
1799 break; /* BLESSED */
1803 break; /* uncursed */
1808 break; /* Otherwise it's random and we're happy
1809 * with what mkobj gave us! */
1812 /* corpsenm is "empty" if -1, random if -2, otherwise specific */
1813 if (o
->corpsenm
!= NON_PM
) {
1814 if (o
->corpsenm
== NON_PM
- 1)
1815 set_corpsenm(otmp
, rndmonnum());
1817 set_corpsenm(otmp
, o
->corpsenm
);
1819 /* set_corpsenm() took care of egg hatch and corpse timers */
1822 otmp
= oname(otmp
, o
->name
.str
);
1825 if (o
->eroded
< 0) {
1826 otmp
->oerodeproof
= 1;
1828 otmp
->oeroded
= (o
->eroded
% 4);
1829 otmp
->oeroded2
= ((o
->eroded
>> 2) % 4);
1833 otmp
->recharged
= (o
->recharged
% 8);
1836 } else if (o
->broken
) {
1838 otmp
->olocked
= 0; /* obj generation may set */
1840 if (o
->trapped
== 0 || o
->trapped
== 1)
1841 otmp
->otrapped
= o
->trapped
;
1844 #ifdef INVISIBLE_OBJECTS
1849 if (o
->quan
> 0 && objects
[otmp
->otyp
].oc_merge
) {
1850 otmp
->quan
= o
->quan
;
1851 otmp
->owt
= weight(otmp
);
1855 if (o
->containment
& SP_OBJ_CONTENT
) {
1856 if (!container_idx
) {
1857 if (!invent_carrying_monster
) {
1858 /*impossible("create_object: no container");*/
1859 /* don't complain, the monster may be gone legally
1860 (eg. unique demon already generated)
1861 TODO: In the case of unique demon lords, they should
1862 get their inventories even when they get generated
1863 outside the des-file. Maybe another data file that
1864 determines what inventories monsters get by default?
1868 struct obj
*objcheck
= otmp
;
1871 for (ci
= 0; ci
< container_idx
; ci
++)
1872 if (container_obj
[ci
] == objcheck
)
1874 remove_object(otmp
);
1875 if (mpickobj(invent_carrying_monster
, otmp
)) {
1878 "container given to monster was merged or deallocated.");
1879 for (ci
= inuse
; ci
< container_idx
- 1; ci
++)
1880 container_obj
[ci
] = container_obj
[ci
+ 1];
1881 container_obj
[container_idx
] = NULL
;
1884 /* we lost track of it. */
1889 struct obj
*cobj
= container_obj
[container_idx
- 1];
1890 remove_object(otmp
);
1892 (void) add_to_container(cobj
, otmp
);
1893 cobj
->owt
= weight(cobj
);
1895 obj_extract_self(otmp
);
1902 if (o
->containment
& SP_OBJ_CONTAINER
) {
1903 delete_contents(otmp
);
1904 if (container_idx
< MAX_CONTAINMENT
) {
1905 container_obj
[container_idx
] = otmp
;
1908 impossible("create_object: too deeply nested containers.");
1911 /* Medusa level special case: statues are petrified monsters, so they
1912 * are not stone-resistant and have monster inventory. They also lack
1913 * other contents, but that can be specified as an empty container.
1915 if (o
->id
== STATUE
&& Is_medusa_level(&u
.uz
) && o
->corpsenm
== NON_PM
) {
1919 int i
= 0; /* prevent endless loop in case makemon always fails */
1921 /* Named random statues are of player types, and aren't stone-
1922 * resistant (if they were, we'd have to reset the name as well as
1923 * setting corpsenm).
1925 for (wastyp
= otmp
->corpsenm
; i
< 1000; i
++, wastyp
= rndmonnum()) {
1926 /* makemon without rndmonst() might create a group */
1927 was
= makemon(&mons
[wastyp
], 0, 0, MM_NOCOUNTBIRTH
);
1929 if (!resists_ston(was
)) {
1930 (void) propagate(wastyp
, TRUE
, FALSE
);
1938 set_corpsenm(otmp
, wastyp
);
1939 while (was
->minvent
) {
1942 obj_extract_self(obj
);
1943 (void) add_to_container(otmp
, obj
);
1945 otmp
->owt
= weight(otmp
);
1950 /* Nasty hack here: try to determine if this is the Mines or Sokoban
1951 * "prize" and then set record_achieve_special (maps to corpsenm)
1952 * for the object. That field will later be checked to find out if
1953 * the player obtained the prize. */
1954 if (is_mines_prize(otmp
) || is_soko_prize(otmp
)) {
1955 otmp
->record_achieve_special
= 1;
1961 begin_burn(otmp
, FALSE
);
1967 (void) bury_an_obj(otmp
, &dealloced
);
1968 if (dealloced
&& container_idx
) {
1969 container_obj
[container_idx
- 1] = NULL
;
1975 * Create an altar in a room.
1978 create_altar(a
, croom
)
1980 struct mkroom
*croom
;
1984 boolean croom_is_temple
= TRUE
;
1988 get_free_room_loc(&x
, &y
, croom
, a
->coord
);
1989 if (croom
->rtype
!= TEMPLE
)
1990 croom_is_temple
= FALSE
;
1992 get_location_coord(&x
, &y
, DRY
, croom
, a
->coord
);
1993 if ((sproom
= (schar
) *in_rooms(x
, y
, TEMPLE
)) != 0)
1994 croom
= &rooms
[sproom
- ROOMOFFSET
];
1996 croom_is_temple
= FALSE
;
1999 /* check for existing features */
2000 oldtyp
= levl
[x
][y
].typ
;
2001 if (oldtyp
== STAIRS
|| oldtyp
== LADDER
)
2004 /* Is the alignment random ?
2005 * If so, it's an 80% chance that the altar will be co-aligned.
2007 * The alignment is encoded as amask values instead of alignment
2008 * values to avoid conflicting with the rest of the encoding,
2009 * shared by many other parts of the special level code.
2011 amask
= (a
->align
== AM_SPLEV_CO
)
2012 ? Align2amask(u
.ualignbase
[A_ORIGINAL
])
2013 : (a
->align
== AM_SPLEV_NONCO
)
2014 ? Align2amask(noncoalignment(u
.ualignbase
[A_ORIGINAL
]))
2015 : (a
->align
== -(MAX_REGISTERS
+ 1))
2017 : (a
->align
< 0 ? ralign
[-a
->align
- 1] : a
->align
);
2019 levl
[x
][y
].typ
= ALTAR
;
2020 levl
[x
][y
].altarmask
= amask
;
2023 a
->shrine
= rn2(2); /* handle random case */
2025 if (!croom_is_temple
|| !a
->shrine
)
2028 if (a
->shrine
) { /* Is it a shrine or sanctum? */
2029 priestini(&u
.uz
, croom
, x
, y
, (a
->shrine
> 1));
2030 levl
[x
][y
].altarmask
|= AM_SHRINE
;
2031 level
.flags
.has_temple
= TRUE
;
2036 replace_terrain(terr
, croom
)
2037 replaceterrain
*terr
;
2038 struct mkroom
*croom
;
2040 schar x
, y
, x1
, y1
, x2
, y2
;
2042 if (terr
->toter
>= MAX_TYPE
)
2047 get_location(&x1
, &y1
, ANY_LOC
, croom
);
2051 get_location(&x2
, &y2
, ANY_LOC
, croom
);
2053 for (x
= max(x1
, 0); x
<= min(x2
, COLNO
- 1); x
++)
2054 for (y
= max(y1
, 0); y
<= min(y2
, ROWNO
- 1); y
++)
2055 if (levl
[x
][y
].typ
== terr
->fromter
&& rn2(100) < terr
->chance
) {
2056 SET_TYPLIT(x
, y
, terr
->toter
, terr
->tolit
);
2061 * Search for a door in a room on a specified wall.
2064 search_door(croom
, x
, y
, wall
, cnt
)
2065 struct mkroom
*croom
;
2099 dx
= dy
= xx
= yy
= 0;
2100 panic("search_door: Bad wall!");
2103 while (xx
<= croom
->hx
+ 1 && yy
<= croom
->hy
+ 1) {
2104 if (IS_DOOR(levl
[xx
][yy
].typ
) || levl
[xx
][yy
].typ
== SDOOR
) {
2117 * Dig a corridor between two points.
2120 dig_corridor(org
, dest
, nxcor
, ftyp
, btyp
)
2125 int dx
= 0, dy
= 0, dix
, diy
, cct
;
2133 if (xx
<= 0 || yy
<= 0 || tx
<= 0 || ty
<= 0 || xx
> COLNO
- 1
2134 || tx
> COLNO
- 1 || yy
> ROWNO
- 1 || ty
> ROWNO
- 1) {
2135 debugpline4("dig_corridor: bad coords <%d,%d> <%d,%d>.",
2151 while (xx
!= tx
|| yy
!= ty
) {
2152 /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
2153 if (cct
++ > 500 || (nxcor
&& !rn2(35)))
2159 if (xx
>= COLNO
- 1 || xx
<= 0 || yy
<= 0 || yy
>= ROWNO
- 1)
2160 return FALSE
; /* impossible */
2162 crm
= &levl
[xx
][yy
];
2163 if (crm
->typ
== btyp
) {
2164 if (ftyp
!= CORR
|| rn2(100)) {
2166 if (nxcor
&& !rn2(50))
2167 (void) mksobj_at(BOULDER
, xx
, yy
, TRUE
, FALSE
);
2171 } else if (crm
->typ
!= ftyp
&& crm
->typ
!= SCORR
) {
2176 /* find next corridor position */
2180 if ((dix
> diy
) && diy
&& !rn2(dix
-diy
+1)) {
2182 } else if ((diy
> dix
) && dix
&& !rn2(diy
-dix
+1)) {
2186 /* do we have to change direction ? */
2187 if (dy
&& dix
> diy
) {
2188 register int ddx
= (xx
> tx
) ? -1 : 1;
2190 crm
= &levl
[xx
+ ddx
][yy
];
2191 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
) {
2196 } else if (dx
&& diy
> dix
) {
2197 register int ddy
= (yy
> ty
) ? -1 : 1;
2199 crm
= &levl
[xx
][yy
+ ddy
];
2200 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
) {
2207 /* continue straight on? */
2208 crm
= &levl
[xx
+ dx
][yy
+ dy
];
2209 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
)
2212 /* no, what must we do now?? */
2215 dy
= (ty
< yy
) ? -1 : 1;
2218 dx
= (tx
< xx
) ? -1 : 1;
2220 crm
= &levl
[xx
+ dx
][yy
+ dy
];
2221 if (crm
->typ
== btyp
|| crm
->typ
== ftyp
|| crm
->typ
== SCORR
)
2230 * Disgusting hack: since special levels have their rooms filled before
2231 * sorting the rooms, we have to re-arrange the speed values upstairs_room
2232 * and dnstairs_room after the rooms have been sorted. On normal levels,
2233 * stairs don't get created until _after_ sorting takes place.
2239 struct mkroom
*croom
;
2242 && !((dnstairs_room
->lx
<= xdnstair
&& xdnstair
<= dnstairs_room
->hx
)
2243 && (dnstairs_room
->ly
<= ydnstair
2244 && ydnstair
<= dnstairs_room
->hy
))) {
2245 for (i
= 0; i
< nroom
; i
++) {
2247 if ((croom
->lx
<= xdnstair
&& xdnstair
<= croom
->hx
)
2248 && (croom
->ly
<= ydnstair
&& ydnstair
<= croom
->hy
)) {
2249 dnstairs_room
= croom
;
2254 panic("Couldn't find dnstair room in fix_stair_rooms!");
2257 && !((upstairs_room
->lx
<= xupstair
&& xupstair
<= upstairs_room
->hx
)
2258 && (upstairs_room
->ly
<= yupstair
2259 && yupstair
<= upstairs_room
->hy
))) {
2260 for (i
= 0; i
< nroom
; i
++) {
2262 if ((croom
->lx
<= xupstair
&& xupstair
<= croom
->hx
)
2263 && (croom
->ly
<= yupstair
&& yupstair
<= croom
->hy
)) {
2264 upstairs_room
= croom
;
2269 panic("Couldn't find upstair room in fix_stair_rooms!");
2274 * Corridors always start from a door. But it can end anywhere...
2275 * Basically we search for door coordinates or for endpoints coordinates
2276 * (from a distance).
2284 if (c
->src
.room
== -1) {
2286 makecorridors(); /*makecorridors(c->src.door);*/
2290 if (!search_door(&rooms
[c
->src
.room
], &org
.x
, &org
.y
, c
->src
.wall
,
2294 if (c
->dest
.room
!= -1) {
2295 if (!search_door(&rooms
[c
->dest
.room
], &dest
.x
, &dest
.y
, c
->dest
.wall
,
2298 switch (c
->src
.wall
) {
2312 switch (c
->dest
.wall
) {
2326 (void) dig_corridor(&org
, &dest
, FALSE
, CORR
, STONE
);
2331 * Fill a room (shop, zoo, etc...) with appropriate stuff.
2334 fill_room(croom
, prefilled
)
2335 struct mkroom
*croom
;
2338 if (!croom
|| croom
->rtype
== OROOM
)
2345 if (croom
->rtype
>= SHOPBASE
) {
2346 stock_room(croom
->rtype
- SHOPBASE
, croom
);
2347 level
.flags
.has_shop
= TRUE
;
2351 switch (croom
->rtype
) {
2353 for (x
= croom
->lx
; x
<= croom
->hx
; x
++)
2354 for (y
= croom
->ly
; y
<= croom
->hy
; y
++)
2355 (void) mkgold((long) rn1(abs(depth(&u
.uz
)) * 100, 51),
2367 switch (croom
->rtype
) {
2369 level
.flags
.has_vault
= TRUE
;
2372 level
.flags
.has_zoo
= TRUE
;
2375 level
.flags
.has_court
= TRUE
;
2378 level
.flags
.has_morgue
= TRUE
;
2381 level
.flags
.has_beehive
= TRUE
;
2384 level
.flags
.has_barracks
= TRUE
;
2387 level
.flags
.has_temple
= TRUE
;
2390 level
.flags
.has_swamp
= TRUE
;
2401 struct mkroom
*aroom
;
2402 xchar rtype
= (!r
->chance
|| rn2(100) < r
->chance
) ? r
->rtype
: OROOM
;
2405 aroom
= &subrooms
[nsubroom
];
2406 okroom
= create_subroom(mkr
, r
->x
, r
->y
, r
->w
, r
->h
, rtype
, r
->rlit
);
2408 aroom
= &rooms
[nroom
];
2409 okroom
= create_room(r
->x
, r
->y
, r
->w
, r
->h
, r
->xalign
, r
->yalign
,
2414 #ifdef SPECIALIZATION
2415 topologize(aroom
, FALSE
); /* set roomno */
2417 topologize(aroom
); /* set roomno */
2419 aroom
->needfill
= r
->filled
;
2420 aroom
->needjoining
= r
->joined
;
2423 return (struct mkroom
*) 0;
2427 * set lighting in a region that will not become a room.
2430 light_region(tmpregion
)
2433 register boolean litstate
= tmpregion
->rlit
? 1 : 0;
2434 register int hiy
= tmpregion
->y2
;
2436 register struct rm
*lev
;
2437 int lowy
= tmpregion
->y1
;
2438 int lowx
= tmpregion
->x1
, hix
= tmpregion
->x2
;
2441 /* adjust region size for walls, but only if lighted */
2442 lowx
= max(lowx
- 1, 1);
2443 hix
= min(hix
+ 1, COLNO
- 1);
2444 lowy
= max(lowy
- 1, 0);
2445 hiy
= min(hiy
+ 1, ROWNO
- 1);
2447 for (x
= lowx
; x
<= hix
; x
++) {
2448 lev
= &levl
[x
][lowy
];
2449 for (y
= lowy
; y
<= hiy
; y
++) {
2450 if (lev
->typ
!= LAVAPOOL
) /* this overrides normal lighting */
2451 lev
->lit
= litstate
;
2458 wallify_map(x1
, y1
, x2
, y2
)
2461 int x
, y
, xx
, yy
, lo_xx
, lo_yy
, hi_xx
, hi_yy
;
2463 for (y
= y1
; y
<= y2
; y
++) {
2464 lo_yy
= (y
> 0) ? y
- 1 : 0;
2465 hi_yy
= (y
< y2
) ? y
+ 1 : y2
;
2466 for (x
= x1
; x
<= x2
; x
++) {
2467 if (levl
[x
][y
].typ
!= STONE
)
2469 lo_xx
= (x
> 0) ? x
- 1 : 0;
2470 hi_xx
= (x
< x2
) ? x
+ 1 : x2
;
2471 for (yy
= lo_yy
; yy
<= hi_yy
; yy
++)
2472 for (xx
= lo_xx
; xx
<= hi_xx
; xx
++)
2473 if (IS_ROOM(levl
[xx
][yy
].typ
)
2474 || levl
[xx
][yy
].typ
== CROSSWALL
) {
2475 levl
[x
][y
].typ
= (yy
!= y
) ? HWALL
: VWALL
;
2476 yy
= hi_yy
; /* end `yy' loop */
2477 break; /* end `xx' loop */
2484 * Select a random coordinate in the maze.
2486 * We want a place not 'touched' by the loader. That is, a place in
2487 * the maze outside every part of the special level.
2490 maze1xy(m
, humidity
)
2494 register int x
, y
, tryct
= 2000;
2495 /* tryct: normally it won't take more than ten or so tries due
2496 to the circumstances under which we'll be called, but the
2497 `humidity' screening might drastically change the chances */
2500 x
= rn1(x_maze_max
- 3, 3);
2501 y
= rn1(y_maze_max
- 3, 3);
2503 break; /* give up */
2504 } while (!(x
% 2) || !(y
% 2) || SpLev_Map
[x
][y
]
2505 || !is_ok_location((schar
) x
, (schar
) y
, humidity
));
2507 m
->x
= (xchar
) x
, m
->y
= (xchar
) y
;
2511 * If there's a significant portion of maze unused by the special level,
2512 * we don't want it empty.
2514 * Makes the number of traps, monsters, etc. proportional
2515 * to the size of the maze.
2520 int mapcountmax
, mapcount
, mapfact
;
2524 mapcountmax
= mapcount
= (x_maze_max
- 2) * (y_maze_max
- 2);
2525 mapcountmax
= mapcountmax
/ 2;
2527 for (x
= 2; x
< x_maze_max
; x
++)
2528 for (y
= 0; y
< y_maze_max
; y
++)
2529 if (SpLev_Map
[x
][y
])
2532 if ((mapcount
> (int) (mapcountmax
/ 10))) {
2533 mapfact
= (int) ((mapcount
* 100L) / mapcountmax
);
2534 for (x
= rnd((int) (20 * mapfact
) / 100); x
; x
--) {
2536 (void) mkobj_at(rn2(2) ? GEM_CLASS
: RANDOM_CLASS
, mm
.x
, mm
.y
,
2539 for (x
= rnd((int) (12 * mapfact
) / 100); x
; x
--) {
2541 (void) mksobj_at(BOULDER
, mm
.x
, mm
.y
, TRUE
, FALSE
);
2543 for (x
= rn2(2); x
; x
--) {
2545 (void) makemon(&mons
[PM_MINOTAUR
], mm
.x
, mm
.y
, NO_MM_FLAGS
);
2547 for (x
= rnd((int) (12 * mapfact
) / 100); x
; x
--) {
2549 (void) makemon((struct permonst
*) 0, mm
.x
, mm
.y
, NO_MM_FLAGS
);
2551 for (x
= rn2((int) (15 * mapfact
) / 100); x
; x
--) {
2553 (void) mkgold(0L, mm
.x
, mm
.y
);
2555 for (x
= rn2((int) (15 * mapfact
) / 100); x
; x
--) {
2559 trytrap
= rndtrap();
2560 if (sobj_at(BOULDER
, mm
.x
, mm
.y
))
2561 while (trytrap
== PIT
|| trytrap
== SPIKED_PIT
2562 || trytrap
== TRAPDOOR
|| trytrap
== HOLE
)
2563 trytrap
= rndtrap();
2564 (void) maketrap(mm
.x
, mm
.y
, trytrap
);
2570 * special level loader
2573 sp_level_loader(fd
, lvl
)
2578 struct opvar
*opdat
;
2581 Fread((genericptr_t
) & (lvl
->n_opcodes
), 1, sizeof(lvl
->n_opcodes
), fd
);
2582 lvl
->opcodes
= (_opcode
*) alloc(sizeof(_opcode
) * (lvl
->n_opcodes
));
2584 while (n_opcode
< lvl
->n_opcodes
) {
2585 Fread((genericptr_t
) &lvl
->opcodes
[n_opcode
].opcode
, 1,
2586 sizeof(lvl
->opcodes
[n_opcode
].opcode
), fd
);
2587 opcode
= lvl
->opcodes
[n_opcode
].opcode
;
2591 if (opcode
< SPO_NULL
|| opcode
>= MAX_SP_OPCODES
)
2592 panic("sp_level_loader: impossible opcode %i.", opcode
);
2594 if (opcode
== SPO_PUSH
) {
2596 struct opvar
*ov
= (struct opvar
*) alloc(sizeof(struct opvar
));
2599 ov
->spovartyp
= SPO_NULL
;
2601 Fread((genericptr_t
) & (ov
->spovartyp
), 1, sizeof(ov
->spovartyp
),
2604 switch (ov
->spovartyp
) {
2609 case SPOVAR_MAPCHAR
:
2613 Fread((genericptr_t
) & (ov
->vardata
.l
), 1,
2614 sizeof(ov
->vardata
.l
), fd
);
2616 case SPOVAR_VARIABLE
:
2621 Fread((genericptr_t
) &nsize
, 1, sizeof(nsize
), fd
);
2622 opd
= (char *) alloc(nsize
+ 1);
2625 Fread(opd
, 1, nsize
, fd
);
2627 ov
->vardata
.str
= opd
;
2631 panic("sp_level_loader: unknown opvar type %i",
2636 lvl
->opcodes
[n_opcode
].opdat
= opdat
;
2643 /* Frees the memory allocated for special level creation structs */
2648 static const char nhFunc
[] = "sp_level_free";
2651 while (n_opcode
< lvl
->n_opcodes
) {
2652 int opcode
= lvl
->opcodes
[n_opcode
].opcode
;
2653 struct opvar
*opdat
= lvl
->opcodes
[n_opcode
].opdat
;
2655 if (opcode
< SPO_NULL
|| opcode
>= MAX_SP_OPCODES
)
2656 panic("sp_level_free: unknown opcode %i", opcode
);
2663 lvl
->opcodes
= NULL
;
2668 splev_initlev(linit
)
2671 switch (linit
->init_style
) {
2673 impossible("Unrecognized level init style.");
2677 case LVLINIT_SOLIDFILL
:
2678 if (linit
->lit
== -1)
2679 linit
->lit
= rn2(2);
2680 lvlfill_solid(linit
->filling
, linit
->lit
);
2682 case LVLINIT_MAZEGRID
:
2683 lvlfill_maze_grid(2, 0, x_maze_max
, y_maze_max
, linit
->filling
);
2689 if (linit
->lit
== -1)
2690 linit
->lit
= rn2(2);
2691 if (linit
->filling
> -1)
2692 lvlfill_solid(linit
->filling
, 0);
2693 linit
->icedpools
= icedpools
;
2703 struct sp_frame
*frame
=
2704 (struct sp_frame
*) alloc(sizeof(struct sp_frame
));
2707 frame
->variables
= NULL
;
2708 frame
->n_opcode
= execptr
;
2709 frame
->stack
= (struct splevstack
*) alloc(sizeof(struct splevstack
));
2710 splev_stack_init(frame
->stack
);
2716 struct sp_frame
*frame
;
2721 splev_stack_done(frame
->stack
);
2722 frame
->stack
= NULL
;
2724 if (frame
->variables
) {
2725 variable_list_del(frame
->variables
);
2726 frame
->variables
= NULL
;
2732 spo_frame_push(coder
)
2733 struct sp_coder
*coder
;
2735 struct sp_frame
*tmpframe
= frame_new(coder
->frame
->n_opcode
);
2737 tmpframe
->next
= coder
->frame
;
2738 coder
->frame
= tmpframe
;
2742 spo_frame_pop(coder
)
2743 struct sp_coder
*coder
;
2745 if (coder
->frame
&& coder
->frame
->next
) {
2746 struct sp_frame
*tmpframe
= coder
->frame
->next
;
2748 frame_del(coder
->frame
);
2749 coder
->frame
= tmpframe
;
2750 coder
->stack
= coder
->frame
->stack
;
2755 sp_code_jmpaddr(curpos
, jmpaddr
)
2756 long curpos
, jmpaddr
;
2758 return (curpos
+ jmpaddr
);
2763 struct sp_coder
*coder
;
2765 static const char nhFunc
[] = "spo_call";
2767 struct opvar
*params
;
2768 struct sp_frame
*tmpframe
;
2770 if (!OV_pop_i(addr
) || !OV_pop_i(params
))
2772 if (OV_i(params
) < 0)
2775 tmpframe
= frame_new(sp_code_jmpaddr(coder
->frame
->n_opcode
,
2778 while (OV_i(params
)-- > 0) {
2779 splev_stack_push(tmpframe
->stack
, splev_stack_getdat_any(coder
));
2781 splev_stack_reverse(tmpframe
->stack
);
2784 tmpframe
->next
= coder
->frame
;
2785 coder
->frame
= tmpframe
;
2793 struct sp_coder
*coder
;
2795 static const char nhFunc
[] = "spo_return";
2796 struct opvar
*params
;
2798 if (!coder
->frame
|| !coder
->frame
->next
)
2799 panic("return: no frame.");
2800 if (!OV_pop_i(params
))
2802 if (OV_i(params
) < 0)
2805 while (OV_i(params
)-- > 0) {
2806 splev_stack_push(coder
->frame
->next
->stack
,
2807 splev_stack_pop(coder
->stack
));
2811 if (coder
->frame
->next
) {
2812 struct sp_frame
*tmpframe
= coder
->frame
->next
;
2813 frame_del(coder
->frame
);
2814 coder
->frame
= tmpframe
;
2815 coder
->stack
= coder
->frame
->stack
;
2823 spo_end_moninvent(coder
)
2824 struct sp_coder
*coder UNUSED
;
2826 if (invent_carrying_monster
)
2827 m_dowear(invent_carrying_monster
, TRUE
);
2828 invent_carrying_monster
= NULL
;
2833 spo_pop_container(coder
)
2834 struct sp_coder
*coder UNUSED
;
2836 if (container_idx
> 0) {
2838 container_obj
[container_idx
] = NULL
;
2844 struct sp_coder
*coder
;
2846 static const char nhFunc
[] = "spo_message";
2857 old_n
= lev_message
? (strlen(lev_message
) + 1) : 0;
2860 levmsg
= (char *) alloc(old_n
+ n
+ 1);
2862 levmsg
[old_n
- 1] = '\n';
2864 (void) memcpy((genericptr_t
) levmsg
, (genericptr_t
) lev_message
,
2866 (void) memcpy((genericptr_t
) &levmsg
[old_n
], msg
, n
);
2867 levmsg
[old_n
+ n
] = '\0';
2869 lev_message
= levmsg
;
2875 struct sp_coder
*coder
;
2877 static const char nhFunc
[] = "spo_monster";
2879 struct opvar
*varparam
;
2880 struct opvar
*id
, *mcoord
, *has_inv
;
2883 tmpmons
.peaceful
= -1;
2884 tmpmons
.asleep
= -1;
2885 tmpmons
.name
.str
= (char *) 0;
2887 tmpmons
.appear_as
.str
= (char *) 0;
2888 tmpmons
.align
= -MAX_REGISTERS
- 2;
2891 tmpmons
.cancelled
= 0;
2892 tmpmons
.revived
= 0;
2894 tmpmons
.fleeing
= 0;
2895 tmpmons
.blinded
= 0;
2896 tmpmons
.paralyzed
= 0;
2897 tmpmons
.stunned
= 0;
2898 tmpmons
.confused
= 0;
2899 tmpmons
.seentraps
= 0;
2900 tmpmons
.has_invent
= 0;
2902 if (!OV_pop_i(has_inv
))
2905 if (!OV_pop_i(varparam
))
2908 while ((nparams
++ < (SP_M_V_END
+ 1)) && (OV_typ(varparam
) == SPOVAR_INT
)
2909 && (OV_i(varparam
) >= 0) && (OV_i(varparam
) < SP_M_V_END
)) {
2910 struct opvar
*parm
= NULL
;
2913 switch (OV_i(varparam
)) {
2915 if ((OV_typ(parm
) == SPOVAR_STRING
) && !tmpmons
.name
.str
)
2916 tmpmons
.name
.str
= dupstr(OV_s(parm
));
2919 if ((OV_typ(parm
) == SPOVAR_INT
) && !tmpmons
.appear_as
.str
) {
2920 tmpmons
.appear
= OV_i(parm
);
2923 tmpmons
.appear_as
.str
= dupstr(OV_s(parm
));
2927 if (OV_typ(parm
) == SPOVAR_INT
)
2928 tmpmons
.asleep
= OV_i(parm
);
2931 if (OV_typ(parm
) == SPOVAR_INT
)
2932 tmpmons
.align
= OV_i(parm
);
2934 case SP_M_V_PEACEFUL
:
2935 if (OV_typ(parm
) == SPOVAR_INT
)
2936 tmpmons
.peaceful
= OV_i(parm
);
2939 if (OV_typ(parm
) == SPOVAR_INT
)
2940 tmpmons
.female
= OV_i(parm
);
2943 if (OV_typ(parm
) == SPOVAR_INT
)
2944 tmpmons
.invis
= OV_i(parm
);
2946 case SP_M_V_CANCELLED
:
2947 if (OV_typ(parm
) == SPOVAR_INT
)
2948 tmpmons
.cancelled
= OV_i(parm
);
2950 case SP_M_V_REVIVED
:
2951 if (OV_typ(parm
) == SPOVAR_INT
)
2952 tmpmons
.revived
= OV_i(parm
);
2955 if (OV_typ(parm
) == SPOVAR_INT
)
2956 tmpmons
.avenge
= OV_i(parm
);
2958 case SP_M_V_FLEEING
:
2959 if (OV_typ(parm
) == SPOVAR_INT
)
2960 tmpmons
.fleeing
= OV_i(parm
);
2962 case SP_M_V_BLINDED
:
2963 if (OV_typ(parm
) == SPOVAR_INT
)
2964 tmpmons
.blinded
= OV_i(parm
);
2966 case SP_M_V_PARALYZED
:
2967 if (OV_typ(parm
) == SPOVAR_INT
)
2968 tmpmons
.paralyzed
= OV_i(parm
);
2970 case SP_M_V_STUNNED
:
2971 if (OV_typ(parm
) == SPOVAR_INT
)
2972 tmpmons
.stunned
= OV_i(parm
);
2974 case SP_M_V_CONFUSED
:
2975 if (OV_typ(parm
) == SPOVAR_INT
)
2976 tmpmons
.confused
= OV_i(parm
);
2978 case SP_M_V_SEENTRAPS
:
2979 if (OV_typ(parm
) == SPOVAR_INT
)
2980 tmpmons
.seentraps
= OV_i(parm
);
2983 nparams
= SP_M_V_END
+ 1;
2986 impossible("MONSTER with unknown variable param type!");
2990 if (OV_i(varparam
) != SP_M_V_END
) {
2991 opvar_free(varparam
);
2996 if (!OV_pop_c(mcoord
))
2997 panic("no monster coord?");
2999 if (!OV_pop_typ(id
, SPOVAR_MONST
))
3000 panic("no mon type");
3002 tmpmons
.id
= SP_MONST_PM(OV_i(id
));
3003 tmpmons
.class = SP_MONST_CLASS(OV_i(id
));
3004 tmpmons
.coord
= OV_i(mcoord
);
3005 tmpmons
.has_invent
= OV_i(has_inv
);
3007 create_monster(&tmpmons
, coder
->croom
);
3009 Free(tmpmons
.name
.str
);
3010 Free(tmpmons
.appear_as
.str
);
3013 opvar_free(has_inv
);
3014 opvar_free(varparam
);
3019 struct sp_coder
*coder
;
3021 static const char nhFunc
[] = "spo_object";
3024 struct opvar
*varparam
;
3025 struct opvar
*id
, *containment
;
3029 tmpobj
.curse_state
= -1;
3030 tmpobj
.corpsenm
= NON_PM
;
3031 tmpobj
.name
.str
= (char *) 0;
3037 tmpobj
.trapped
= -1;
3038 tmpobj
.recharged
= 0;
3042 tmpobj
.coord
= SP_COORD_PACK_RANDOM(0);
3044 if (!OV_pop_i(containment
))
3047 if (!OV_pop_i(varparam
))
3050 while ((nparams
++ < (SP_O_V_END
+ 1)) && (OV_typ(varparam
) == SPOVAR_INT
)
3051 && (OV_i(varparam
) >= 0) && (OV_i(varparam
) < SP_O_V_END
)) {
3054 switch (OV_i(varparam
)) {
3056 if ((OV_typ(parm
) == SPOVAR_STRING
) && !tmpobj
.name
.str
)
3057 tmpobj
.name
.str
= dupstr(OV_s(parm
));
3059 case SP_O_V_CORPSENM
:
3060 if (OV_typ(parm
) == SPOVAR_MONST
) {
3061 char monclass
= SP_MONST_CLASS(OV_i(parm
));
3062 int monid
= SP_MONST_PM(OV_i(parm
));
3064 if (monid
>= 0 && monid
< NUMMONS
) {
3065 tmpobj
.corpsenm
= monid
;
3066 break; /* we're done! */
3068 struct permonst
*pm
= (struct permonst
*) 0;
3069 if (def_char_to_monclass(monclass
) != MAXMCLASSES
) {
3070 pm
= mkclass(def_char_to_monclass(monclass
), G_NOGEN
);
3075 tmpobj
.corpsenm
= monsndx(pm
);
3080 if (OV_typ(parm
) == SPOVAR_INT
)
3081 tmpobj
.curse_state
= OV_i(parm
);
3084 if (OV_typ(parm
) == SPOVAR_INT
)
3085 tmpobj
.spe
= OV_i(parm
);
3088 if (OV_typ(parm
) == SPOVAR_INT
)
3089 tmpobj
.quan
= OV_i(parm
);
3092 if (OV_typ(parm
) == SPOVAR_INT
)
3093 tmpobj
.buried
= OV_i(parm
);
3096 if (OV_typ(parm
) == SPOVAR_INT
)
3097 tmpobj
.lit
= OV_i(parm
);
3100 if (OV_typ(parm
) == SPOVAR_INT
)
3101 tmpobj
.eroded
= OV_i(parm
);
3104 if (OV_typ(parm
) == SPOVAR_INT
)
3105 tmpobj
.locked
= OV_i(parm
);
3107 case SP_O_V_TRAPPED
:
3108 if (OV_typ(parm
) == SPOVAR_INT
)
3109 tmpobj
.trapped
= OV_i(parm
);
3111 case SP_O_V_RECHARGED
:
3112 if (OV_typ(parm
) == SPOVAR_INT
)
3113 tmpobj
.recharged
= OV_i(parm
);
3116 if (OV_typ(parm
) == SPOVAR_INT
)
3117 tmpobj
.invis
= OV_i(parm
);
3119 case SP_O_V_GREASED
:
3120 if (OV_typ(parm
) == SPOVAR_INT
)
3121 tmpobj
.greased
= OV_i(parm
);
3124 if (OV_typ(parm
) == SPOVAR_INT
)
3125 tmpobj
.broken
= OV_i(parm
);
3128 if (OV_typ(parm
) != SPOVAR_COORD
)
3129 panic("no coord for obj?");
3130 tmpobj
.coord
= OV_i(parm
);
3133 nparams
= SP_O_V_END
+ 1;
3136 impossible("OBJECT with unknown variable param type!");
3140 if (OV_i(varparam
) != SP_O_V_END
) {
3141 opvar_free(varparam
);
3146 if (!OV_pop_typ(id
, SPOVAR_OBJ
))
3147 panic("no obj type");
3149 tmpobj
.id
= SP_OBJ_TYP(OV_i(id
));
3150 tmpobj
.class = SP_OBJ_CLASS(OV_i(id
));
3151 tmpobj
.containment
= OV_i(containment
);
3153 quancnt
= (tmpobj
.id
> STRANGE_OBJECT
) ? tmpobj
.quan
: 0;
3156 create_object(&tmpobj
, coder
->croom
);
3158 } while ((quancnt
> 0) && ((tmpobj
.id
> STRANGE_OBJECT
)
3159 && !objects
[tmpobj
.id
].oc_merge
));
3161 Free(tmpobj
.name
.str
);
3162 opvar_free(varparam
);
3164 opvar_free(containment
);
3168 spo_level_flags(coder
)
3169 struct sp_coder
*coder
;
3171 static const char nhFunc
[] = "spo_level_flags";
3172 struct opvar
*flagdata
;
3175 if (!OV_pop_i(flagdata
))
3177 lflags
= OV_i(flagdata
);
3179 if (lflags
& NOTELEPORT
)
3180 level
.flags
.noteleport
= 1;
3181 if (lflags
& HARDFLOOR
)
3182 level
.flags
.hardfloor
= 1;
3183 if (lflags
& NOMMAP
)
3184 level
.flags
.nommap
= 1;
3185 if (lflags
& SHORTSIGHTED
)
3186 level
.flags
.shortsighted
= 1;
3187 if (lflags
& ARBOREAL
)
3188 level
.flags
.arboreal
= 1;
3189 if (lflags
& MAZELEVEL
)
3190 level
.flags
.is_maze_lev
= 1;
3191 if (lflags
& PREMAPPED
)
3192 coder
->premapped
= TRUE
;
3193 if (lflags
& SHROUD
)
3194 level
.flags
.hero_memory
= 0;
3195 if (lflags
& GRAVEYARD
)
3196 level
.flags
.graveyard
= 1;
3197 if (lflags
& ICEDPOOLS
)
3199 if (lflags
& SOLIDIFY
)
3200 coder
->solidify
= TRUE
;
3201 if (lflags
& CORRMAZE
)
3202 level
.flags
.corrmaze
= TRUE
;
3203 if (lflags
& CHECK_INACCESSIBLES
)
3204 coder
->check_inaccessibles
= TRUE
;
3206 opvar_free(flagdata
);
3210 spo_initlevel(coder
)
3211 struct sp_coder
*coder
;
3213 static const char nhFunc
[] = "spo_initlevel";
3215 struct opvar
*init_style
, *fg
, *bg
, *smoothed
, *joined
, *lit
, *walled
,
3218 if (!OV_pop_i(fg
) || !OV_pop_i(bg
) || !OV_pop_i(smoothed
)
3219 || !OV_pop_i(joined
) || !OV_pop_i(lit
) || !OV_pop_i(walled
)
3220 || !OV_pop_i(filling
) || !OV_pop_i(init_style
))
3223 splev_init_present
= TRUE
;
3225 init_lev
.init_style
= OV_i(init_style
);
3226 init_lev
.fg
= OV_i(fg
);
3227 init_lev
.bg
= OV_i(bg
);
3228 init_lev
.smoothed
= OV_i(smoothed
);
3229 init_lev
.joined
= OV_i(joined
);
3230 init_lev
.lit
= OV_i(lit
);
3231 init_lev
.walled
= OV_i(walled
);
3232 init_lev
.filling
= OV_i(filling
);
3234 coder
->lvl_is_joined
= OV_i(joined
);
3236 splev_initlev(&init_lev
);
3238 opvar_free(init_style
);
3241 opvar_free(smoothed
);
3245 opvar_free(filling
);
3249 spo_engraving(coder
)
3250 struct sp_coder
*coder
;
3252 static const char nhFunc
[] = "spo_engraving";
3253 struct opvar
*etyp
, *txt
, *ecoord
;
3256 if (!OV_pop_i(etyp
) || !OV_pop_s(txt
) || !OV_pop_c(ecoord
))
3259 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(ecoord
));
3260 make_engr_at(x
, y
, OV_s(txt
), 0L, OV_i(etyp
));
3268 spo_mineralize(coder
)
3269 struct sp_coder
*coder
;
3271 static const char nhFunc
[] = "spo_mineralize";
3272 struct opvar
*kelp_pool
, *kelp_moat
, *gold_prob
, *gem_prob
;
3274 if (!OV_pop_i(gem_prob
) || !OV_pop_i(gold_prob
) || !OV_pop_i(kelp_moat
)
3275 || !OV_pop_i(kelp_pool
))
3278 mineralize(OV_i(kelp_pool
), OV_i(kelp_moat
), OV_i(gold_prob
),
3279 OV_i(gem_prob
), TRUE
);
3281 opvar_free(gem_prob
);
3282 opvar_free(gold_prob
);
3283 opvar_free(kelp_moat
);
3284 opvar_free(kelp_pool
);
3289 struct sp_coder
*coder
;
3291 static const char nhFunc
[] = "spo_room";
3293 if (coder
->n_subroom
> MAX_NESTED_ROOMS
) {
3294 panic("Too deeply nested rooms?!");
3296 struct opvar
*rflags
, *h
, *w
, *yalign
, *xalign
, *y
, *x
, *rlit
,
3299 struct mkroom
*tmpcr
;
3301 if (!OV_pop_i(h
) || !OV_pop_i(w
) || !OV_pop_i(y
) || !OV_pop_i(x
)
3302 || !OV_pop_i(yalign
) || !OV_pop_i(xalign
) || !OV_pop_i(rflags
)
3303 || !OV_pop_i(rlit
) || !OV_pop_i(chance
) || !OV_pop_i(rtype
))
3306 tmproom
.x
= OV_i(x
);
3307 tmproom
.y
= OV_i(y
);
3308 tmproom
.w
= OV_i(w
);
3309 tmproom
.h
= OV_i(h
);
3310 tmproom
.xalign
= OV_i(xalign
);
3311 tmproom
.yalign
= OV_i(yalign
);
3312 tmproom
.rtype
= OV_i(rtype
);
3313 tmproom
.chance
= OV_i(chance
);
3314 tmproom
.rlit
= OV_i(rlit
);
3315 tmproom
.filled
= (OV_i(rflags
) & (1 << 0));
3316 /*tmproom.irregular = (OV_i(rflags) & (1 << 1));*/
3317 tmproom
.joined
= !(OV_i(rflags
) & (1 << 2));
3330 if (!coder
->failed_room
[coder
->n_subroom
- 1]) {
3331 tmpcr
= build_room(&tmproom
, coder
->croom
);
3333 coder
->tmproomlist
[coder
->n_subroom
] = tmpcr
;
3334 coder
->failed_room
[coder
->n_subroom
] = FALSE
;
3338 } /* failed to create parent room, so fail this too */
3340 coder
->tmproomlist
[coder
->n_subroom
] = (struct mkroom
*) 0;
3341 coder
->failed_room
[coder
->n_subroom
] = TRUE
;
3347 struct sp_coder
*coder
;
3349 if (coder
->n_subroom
> 1) {
3351 coder
->tmproomlist
[coder
->n_subroom
] = NULL
;
3352 coder
->failed_room
[coder
->n_subroom
] = TRUE
;
3354 /* no subroom, get out of top-level room */
3355 /* Need to ensure xstart/ystart/xsize/ysize have something sensible,
3356 in case there's some stuff to be created outside the outermost
3360 if (xsize
<= 1 && ysize
<= 1) {
3371 struct sp_coder
*coder
;
3373 static const char nhFunc
[] = "spo_stair";
3375 struct opvar
*up
, *scoord
;
3376 struct trap
*badtrap
;
3378 if (!OV_pop_i(up
) || !OV_pop_c(scoord
))
3381 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(scoord
));
3382 if ((badtrap
= t_at(x
, y
)) != 0)
3384 mkstairs(x
, y
, (char) OV_i(up
), coder
->croom
);
3385 SpLev_Map
[x
][y
] = 1;
3393 struct sp_coder
*coder
;
3395 static const char nhFunc
[] = "spo_ladder";
3397 struct opvar
*up
, *lcoord
;
3399 if (!OV_pop_i(up
) || !OV_pop_c(lcoord
))
3402 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(lcoord
));
3404 levl
[x
][y
].typ
= LADDER
;
3405 SpLev_Map
[x
][y
] = 1;
3409 levl
[x
][y
].ladder
= LA_UP
;
3413 levl
[x
][y
].ladder
= LA_DOWN
;
3421 struct sp_coder
*coder
;
3423 static const char nhFunc
[] = "spo_grave";
3424 struct opvar
*gcoord
, *typ
, *txt
;
3427 if (!OV_pop_i(typ
) || !OV_pop_s(txt
) || !OV_pop_c(gcoord
))
3430 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(gcoord
));
3432 if (isok(x
, y
) && !t_at(x
, y
)) {
3433 levl
[x
][y
].typ
= GRAVE
;
3434 switch (OV_i(typ
)) {
3436 make_grave(x
, y
, OV_s(txt
));
3439 make_grave(x
, y
, NULL
);
3454 struct sp_coder
*coder
;
3456 static const char nhFunc
[] = "spo_altar";
3457 struct opvar
*al
, *shrine
, *acoord
;
3460 if (!OV_pop_i(al
) || !OV_pop_i(shrine
) || !OV_pop_c(acoord
))
3463 tmpaltar
.coord
= OV_i(acoord
);
3464 tmpaltar
.align
= OV_i(al
);
3465 tmpaltar
.shrine
= OV_i(shrine
);
3467 create_altar(&tmpaltar
, coder
->croom
);
3476 struct sp_coder
*coder
;
3478 static const char nhFunc
[] = "spo_trap";
3480 struct opvar
*tcoord
;
3483 if (!OV_pop_i(type
) || !OV_pop_c(tcoord
))
3486 tmptrap
.coord
= OV_i(tcoord
);
3487 tmptrap
.type
= OV_i(type
);
3489 create_trap(&tmptrap
, coder
->croom
);
3496 struct sp_coder
*coder
;
3498 static const char nhFunc
[] = "spo_gold";
3499 struct opvar
*gcoord
, *amt
;
3503 if (!OV_pop_c(gcoord
) || !OV_pop_i(amt
))
3506 get_location_coord(&x
, &y
, DRY
, coder
->croom
, OV_i(gcoord
));
3509 mkgold(amount
, x
, y
);
3516 struct sp_coder
*coder
;
3518 static const char nhFunc
[] = "spo_corridor";
3519 struct opvar
*deswall
, *desdoor
, *desroom
, *srcwall
, *srcdoor
, *srcroom
;
3522 if (!OV_pop_i(deswall
) || !OV_pop_i(desdoor
) || !OV_pop_i(desroom
)
3523 || !OV_pop_i(srcwall
) || !OV_pop_i(srcdoor
) || !OV_pop_i(srcroom
))
3526 tc
.src
.room
= OV_i(srcroom
);
3527 tc
.src
.door
= OV_i(srcdoor
);
3528 tc
.src
.wall
= OV_i(srcwall
);
3529 tc
.dest
.room
= OV_i(desroom
);
3530 tc
.dest
.door
= OV_i(desdoor
);
3531 tc
.dest
.wall
= OV_i(deswall
);
3533 create_corridor(&tc
);
3535 opvar_free(deswall
);
3536 opvar_free(desdoor
);
3537 opvar_free(desroom
);
3538 opvar_free(srcwall
);
3539 opvar_free(srcdoor
);
3540 opvar_free(srcroom
);
3544 selection_opvar(nbuf
)
3548 char buf
[(COLNO
* ROWNO
) + 1];
3551 (void) memset(buf
, 1, sizeof(buf
));
3552 buf
[(COLNO
* ROWNO
)] = '\0';
3553 ov
= opvar_new_str(buf
);
3555 ov
= opvar_new_str(nbuf
);
3557 ov
->spovartyp
= SPOVAR_SEL
;
3562 selection_getpoint(x
, y
, ov
)
3566 if (!ov
|| ov
->spovartyp
!= SPOVAR_SEL
)
3568 if (x
< 0 || y
< 0 || x
>= COLNO
|| y
>= ROWNO
)
3571 return (ov
->vardata
.str
[COLNO
* y
+ x
] - 1);
3575 selection_setpoint(x
, y
, ov
, c
)
3580 if (!ov
|| ov
->spovartyp
!= SPOVAR_SEL
)
3582 if (x
< 0 || y
< 0 || x
>= COLNO
|| y
>= ROWNO
)
3585 ov
->vardata
.str
[COLNO
* y
+ x
] = (char) (c
+ 1);
3595 ov
= selection_opvar((char *) 0);
3599 for (x
= 0; x
< COLNO
; x
++)
3600 for (y
= 0; y
< ROWNO
; y
++)
3601 if (!selection_getpoint(x
, y
, s
))
3602 selection_setpoint(x
, y
, ov
, 1);
3608 selection_logical_oper(s1
, s2
, oper
)
3609 struct opvar
*s1
, *s2
;
3615 ov
= selection_opvar((char *) 0);
3619 for (x
= 0; x
< COLNO
; x
++)
3620 for (y
= 0; y
< ROWNO
; y
++) {
3624 if (selection_getpoint(x
, y
, s1
)
3625 || selection_getpoint(x
, y
, s2
))
3626 selection_setpoint(x
, y
, ov
, 1);
3629 if (selection_getpoint(x
, y
, s1
)
3630 && selection_getpoint(x
, y
, s2
))
3631 selection_setpoint(x
, y
, ov
, 1);
3640 selection_filter_mapchar(ov
, mc
)
3647 struct opvar
*ret
= selection_opvar((char *) 0);
3649 if (!ov
|| !mc
|| !ret
)
3651 mapc
= SP_MAPCHAR_TYP(OV_i(mc
));
3652 lit
= SP_MAPCHAR_LIT(OV_i(mc
));
3653 for (x
= 0; x
< COLNO
; x
++)
3654 for (y
= 0; y
< ROWNO
; y
++)
3655 if (selection_getpoint(x
, y
, ov
) && (levl
[x
][y
].typ
== mapc
)) {
3659 selection_setpoint(x
, y
, ret
, 1);
3662 selection_setpoint(x
, y
, ret
, rn2(2));
3666 if (levl
[x
][y
].lit
== lit
)
3667 selection_setpoint(x
, y
, ret
, 1);
3675 selection_filter_percent(ov
, percent
)
3683 for (x
= 0; x
< COLNO
; x
++)
3684 for (y
= 0; y
< ROWNO
; y
++)
3685 if (selection_getpoint(x
, y
, ov
) && (rn2(100) >= percent
))
3686 selection_setpoint(x
, y
, ov
, 0);
3690 selection_rndcoord(ov
, x
, y
, removeit
)
3699 for (dx
= 0; dx
< COLNO
; dx
++)
3700 for (dy
= 0; dy
< ROWNO
; dy
++)
3701 if (isok(dx
, dy
) && selection_getpoint(dx
, dy
, ov
))
3706 for (dx
= 0; dx
< COLNO
; dx
++)
3707 for (dy
= 0; dy
< ROWNO
; dy
++)
3708 if (isok(dx
, dy
) && selection_getpoint(dx
, dy
, ov
)) {
3712 if (removeit
) selection_setpoint(dx
, dy
, ov
, 0);
3723 selection_do_grow(ov
, dir
)
3728 char tmp
[COLNO
][ROWNO
];
3730 if (ov
->spovartyp
!= SPOVAR_SEL
)
3735 (void) memset(tmp
, 0, sizeof(tmp
));
3737 for (x
= 0; x
< COLNO
; x
++)
3738 for (y
= 0; y
< ROWNO
; y
++) {
3740 if ((dir
& W_WEST
) && (x
> 0)
3741 && (selection_getpoint(x
- 1, y
, ov
)))
3743 if ((dir
& (W_WEST
| W_NORTH
)) && (x
> 0) && (y
> 0)
3744 && (selection_getpoint(x
- 1, y
- 1, ov
)))
3746 if ((dir
& W_NORTH
) && (y
> 0)
3747 && (selection_getpoint(x
, y
- 1, ov
)))
3749 if ((dir
& (W_NORTH
| W_EAST
)) && (y
> 0) && (x
< COLNO
- 1)
3750 && (selection_getpoint(x
+ 1, y
- 1, ov
)))
3752 if ((dir
& W_EAST
) && (x
< COLNO
- 1)
3753 && (selection_getpoint(x
+ 1, y
, ov
)))
3755 if ((dir
& (W_EAST
| W_SOUTH
)) && (x
< COLNO
- 1)
3756 && (y
< ROWNO
- 1) && (selection_getpoint(x
+ 1, y
+ 1, ov
)))
3758 if ((dir
& W_SOUTH
) && (y
< ROWNO
- 1)
3759 && (selection_getpoint(x
, y
+ 1, ov
)))
3761 if ((dir
& (W_SOUTH
| W_WEST
)) && (y
< ROWNO
- 1) && (x
> 0)
3762 && (selection_getpoint(x
- 1, y
+ 1, ov
)))
3768 for (x
= 0; x
< COLNO
; x
++)
3769 for (y
= 0; y
< ROWNO
; y
++)
3771 selection_setpoint(x
, y
, ov
, 1);
3774 STATIC_VAR
int FDECL((*selection_flood_check_func
), (int, int));
3775 STATIC_VAR schar floodfillchk_match_under_typ
;
3778 set_selection_floodfillchk(f
)
3779 int FDECL((*f
), (int, int));
3781 selection_flood_check_func
= f
;
3785 floodfillchk_match_under(x
,y
)
3788 return (floodfillchk_match_under_typ
== levl
[x
][y
].typ
);
3792 floodfillchk_match_accessible(x
, y
)
3795 return (ACCESSIBLE(levl
[x
][y
].typ
)
3796 || levl
[x
][y
].typ
== SDOOR
3797 || levl
[x
][y
].typ
== SCORR
);
3801 selection_floodfill(ov
, x
, y
, diagonals
)
3806 static const char nhFunc
[] = "selection_floodfill";
3807 struct opvar
*tmp
= selection_opvar((char *) 0);
3808 #define SEL_FLOOD_STACK (COLNO * ROWNO)
3809 #define SEL_FLOOD(nx, ny) \
3811 if (idx < SEL_FLOOD_STACK) { \
3816 panic(floodfill_stack_overrun); \
3818 #define SEL_FLOOD_CHKDIR(mx,my,sel) \
3819 if (isok((mx), (my)) \
3820 && (*selection_flood_check_func)((mx), (my)) \
3821 && !selection_getpoint((mx), (my), (sel))) \
3822 SEL_FLOOD((mx), (my))
3823 static const char floodfill_stack_overrun
[] = "floodfill stack overrun";
3825 xchar dx
[SEL_FLOOD_STACK
];
3826 xchar dy
[SEL_FLOOD_STACK
];
3828 if (selection_flood_check_func
== NULL
) {
3838 selection_setpoint(x
, y
, ov
, 1);
3839 selection_setpoint(x
, y
, tmp
, 1);
3841 SEL_FLOOD_CHKDIR((x
+ 1), y
, tmp
);
3842 SEL_FLOOD_CHKDIR((x
- 1), y
, tmp
);
3843 SEL_FLOOD_CHKDIR(x
, (y
+ 1), tmp
);
3844 SEL_FLOOD_CHKDIR(x
, (y
- 1), tmp
);
3846 SEL_FLOOD_CHKDIR((x
+ 1), (y
+ 1), tmp
);
3847 SEL_FLOOD_CHKDIR((x
- 1), (y
- 1), tmp
);
3848 SEL_FLOOD_CHKDIR((x
- 1), (y
+ 1), tmp
);
3849 SEL_FLOOD_CHKDIR((x
+ 1), (y
- 1), tmp
);
3853 #undef SEL_FLOOD_STACK
3854 #undef SEL_FLOOD_CHKDIR
3858 /* McIlroy's Ellipse Algorithm */
3860 selection_do_ellipse(ov
, xc
, yc
, a
, b
, filled
)
3862 int xc
, yc
, a
, b
, filled
;
3863 { /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
3865 long a2
= (long) a
* a
, b2
= (long) b
* b
;
3866 long crit1
= -(a2
/ 4 + a
% 2 + b2
);
3867 long crit2
= -(b2
/ 4 + b
% 2 + a2
);
3868 long crit3
= -(b2
/ 4 + b
% 2);
3869 long t
= -a2
* y
; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
3870 long dxt
= 2 * b2
* x
, dyt
= -2 * a2
* y
;
3871 long d2xt
= 2 * b2
, d2yt
= 2 * a2
;
3881 while (y
>= 0 && x
<= a
) {
3882 selection_setpoint(xc
+ x
, yc
+ y
, ov
, 1);
3883 if (x
!= 0 || y
!= 0)
3884 selection_setpoint(xc
- x
, yc
- y
, ov
, 1);
3885 if (x
!= 0 && y
!= 0) {
3886 selection_setpoint(xc
+ x
, yc
- y
, ov
, 1);
3887 selection_setpoint(xc
- x
, yc
+ y
, ov
, 1);
3889 if (t
+ b2
* x
<= crit1
/* e(x+1,y-1/2) <= 0 */
3890 || t
+ a2
* y
<= crit3
) { /* e(x+1/2,y) <= 0 */
3894 } else if (t
- a2
* y
> crit2
) { /* e(x+1/2,y-1) > 0 */
3908 while (y
>= 0 && x
<= a
) {
3909 if (t
+ b2
* x
<= crit1
/* e(x+1,y-1/2) <= 0 */
3910 || t
+ a2
* y
<= crit3
) { /* e(x+1/2,y) <= 0 */
3915 } else if (t
- a2
* y
> crit2
) { /* e(x+1/2,y-1) > 0 */
3916 for (i
= 0; i
< width
; i
++)
3917 selection_setpoint(xc
- x
+ i
, yc
- y
, ov
, 1);
3919 for (i
= 0; i
< width
; i
++)
3920 selection_setpoint(xc
- x
+ i
, yc
+ y
, ov
, 1);
3925 for (i
= 0; i
< width
; i
++)
3926 selection_setpoint(xc
- x
+ i
, yc
- y
, ov
, 1);
3928 for (i
= 0; i
< width
; i
++)
3929 selection_setpoint(xc
- x
+ i
, yc
+ y
, ov
, 1);
3942 /* distance from line segment (x1,y1, x2,y2) to point (x3,y3) */
3944 line_dist_coord(x1
, y1
, x2
, y2
, x3
, y3
)
3945 long x1
, y1
, x2
, y2
, x3
, y3
;
3949 long s
= px
* px
+ py
* py
;
3950 long x
, y
, dx
, dy
, dist
= 0;
3953 if (x1
== x2
&& y1
== y2
)
3954 return isqrt(dist2(x1
, y1
, x3
, y3
));
3956 lu
= ((x3
- x1
) * px
+ (y3
- y1
) * py
) / (float) s
;
3966 dist
= isqrt(dx
* dx
+ dy
* dy
);
3972 selection_do_gradient(ov
, x
, y
, x2
, y2
, gtyp
, mind
, maxd
, limit
)
3974 long x
, y
, x2
, y2
, gtyp
, mind
, maxd
, limit
;
3990 case SEL_GRADIENT_RADIAL
: {
3991 for (dx
= 0; dx
< COLNO
; dx
++)
3992 for (dy
= 0; dy
< ROWNO
; dy
++) {
3993 long d0
= line_dist_coord(x
, y
, x2
, y2
, dx
, dy
);
3994 if (d0
>= mind
&& (!limit
|| d0
<= maxd
)) {
3995 if (d0
- mind
> rn2(dofs
))
3996 selection_setpoint(dx
, dy
, ov
, 1);
4001 case SEL_GRADIENT_SQUARE
: {
4002 for (dx
= 0; dx
< COLNO
; dx
++)
4003 for (dy
= 0; dy
< ROWNO
; dy
++) {
4004 long d1
= line_dist_coord(x
, y
, x2
, y2
, x
, dy
);
4005 long d2
= line_dist_coord(x
, y
, x2
, y2
, dx
, y
);
4006 long d3
= line_dist_coord(x
, y
, x2
, y2
, x2
, dy
);
4007 long d4
= line_dist_coord(x
, y
, x2
, y2
, dx
, y2
);
4008 long d5
= line_dist_coord(x
, y
, x2
, y2
, dx
, dy
);
4009 long d0
= min(d5
, min(max(d1
, d2
), max(d3
, d4
)));
4011 if (d0
>= mind
&& (!limit
|| d0
<= maxd
)) {
4012 if (d0
- mind
> rn2(dofs
))
4013 selection_setpoint(dx
, dy
, ov
, 1);
4021 /* bresenham line algo */
4023 selection_do_line(x1
, y1
, x2
, y2
, ov
)
4024 schar x1
, y1
, x2
, y2
;
4027 int d0
, dx
, dy
, ai
, bi
, xi
, yi
;
4045 selection_setpoint(x1
, y1
, ov
, 1);
4058 selection_setpoint(x1
, y1
, ov
, 1);
4071 selection_setpoint(x1
, y1
, ov
, 1);
4077 selection_do_randline(x1
, y1
, x2
, y2
, rough
, rec
, ov
)
4078 schar x1
, y1
, x2
, y2
, rough
, rec
;
4088 if ((x2
== x1
) && (y2
== y1
)) {
4089 selection_setpoint(x1
, y1
, ov
, 1);
4093 if (rough
> max(abs(x2
- x1
), abs(y2
- y1
)))
4094 rough
= max(abs(x2
- x1
), abs(y2
- y1
));
4097 mx
= ((x1
+ x2
) / 2);
4098 my
= ((y1
+ y2
) / 2);
4101 dx
= rn2(rough
) - (rough
/ 2);
4102 dy
= rn2(rough
) - (rough
/ 2);
4103 mx
= ((x1
+ x2
) / 2) + dx
;
4104 my
= ((y1
+ y2
) / 2) + dy
;
4105 } while ((mx
> COLNO
- 1 || mx
< 0 || my
< 0 || my
> ROWNO
- 1));
4108 selection_setpoint(mx
, my
, ov
, 1);
4110 rough
= (rough
* 2) / 3;
4114 selection_do_randline(x1
, y1
, mx
, my
, rough
, rec
, ov
);
4115 selection_do_randline(mx
, my
, x2
, y2
, rough
, rec
, ov
);
4119 selection_iterate(ov
, func
, arg
)
4121 select_iter_func func
;
4126 /* yes, this is very naive, but it's not _that_ expensive. */
4127 for (x
= 0; x
< COLNO
; x
++)
4128 for (y
= 0; y
< ROWNO
; y
++)
4129 if (selection_getpoint(x
, y
, ov
))
4134 sel_set_ter(x
, y
, arg
)
4140 terr
= *(terrain
*) arg
;
4141 SET_TYPLIT(x
, y
, terr
.ter
, terr
.tlit
);
4142 /* handle doors and secret doors */
4143 if (levl
[x
][y
].typ
== SDOOR
|| IS_DOOR(levl
[x
][y
].typ
)) {
4144 if (levl
[x
][y
].typ
== SDOOR
)
4145 levl
[x
][y
].doormask
= D_CLOSED
;
4146 if (x
&& (IS_WALL(levl
[x
- 1][y
].typ
) || levl
[x
- 1][y
].horizontal
))
4147 levl
[x
][y
].horizontal
= 1;
4152 sel_set_feature(x
, y
, arg
)
4156 if (IS_FURNITURE(levl
[x
][y
].typ
))
4158 levl
[x
][y
].typ
= (*(int *) arg
);
4162 sel_set_door(dx
, dy
, arg
)
4166 xchar typ
= *(xchar
*) arg
;
4170 if (!IS_DOOR(levl
[x
][y
].typ
) && levl
[x
][y
].typ
!= SDOOR
)
4171 levl
[x
][y
].typ
= (typ
& D_SECRET
) ? SDOOR
: DOOR
;
4172 if (typ
& D_SECRET
) {
4177 levl
[x
][y
].doormask
= typ
;
4178 SpLev_Map
[x
][y
] = 1;
4183 struct sp_coder
*coder
;
4185 static const char nhFunc
[] = "spo_door";
4186 struct opvar
*msk
, *sel
;
4189 if (!OV_pop_i(msk
) || !OV_pop_typ(sel
, SPOVAR_SEL
))
4192 typ
= OV_i(msk
) == -1 ? rnddoor() : (xchar
) OV_i(msk
);
4194 selection_iterate(sel
, sel_set_door
, (genericptr_t
) &typ
);
4202 struct sp_coder
*coder
;
4204 static const char nhFunc
[] = "spo_feature";
4208 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
4211 switch (coder
->opcode
) {
4213 impossible("spo_feature called with wrong opcode %i.", coder
->opcode
);
4225 selection_iterate(sel
, sel_set_feature
, (genericptr_t
) &typ
);
4231 struct sp_coder
*coder
;
4233 static const char nhFunc
[] = "spo_terrain";
4235 struct opvar
*ter
, *sel
;
4237 if (!OV_pop_typ(ter
, SPOVAR_MAPCHAR
) || !OV_pop_typ(sel
, SPOVAR_SEL
))
4240 tmpterrain
.ter
= SP_MAPCHAR_TYP(OV_i(ter
));
4241 tmpterrain
.tlit
= SP_MAPCHAR_LIT(OV_i(ter
));
4242 selection_iterate(sel
, sel_set_ter
, (genericptr_t
) &tmpterrain
);
4249 spo_replace_terrain(coder
)
4250 struct sp_coder
*coder
;
4252 static const char nhFunc
[] = "spo_replace_terrain";
4254 struct opvar
*reg
, *from_ter
, *to_ter
, *chance
;
4256 if (!OV_pop_i(chance
) || !OV_pop_typ(to_ter
, SPOVAR_MAPCHAR
)
4257 || !OV_pop_typ(from_ter
, SPOVAR_MAPCHAR
) || !OV_pop_r(reg
))
4260 rt
.chance
= OV_i(chance
);
4261 rt
.tolit
= SP_MAPCHAR_LIT(OV_i(to_ter
));
4262 rt
.toter
= SP_MAPCHAR_TYP(OV_i(to_ter
));
4263 rt
.fromter
= SP_MAPCHAR_TYP(OV_i(from_ter
));
4264 /* TODO: use SP_MAPCHAR_LIT(OV_i(from_ter)) too */
4265 rt
.x1
= SP_REGION_X1(OV_i(reg
));
4266 rt
.y1
= SP_REGION_Y1(OV_i(reg
));
4267 rt
.x2
= SP_REGION_X2(OV_i(reg
));
4268 rt
.y2
= SP_REGION_Y2(OV_i(reg
));
4270 replace_terrain(&rt
, coder
->croom
);
4273 opvar_free(from_ter
);
4279 generate_way_out_method(nx
,ny
, ov
)
4283 static const char nhFunc
[] = "generate_way_out_method";
4284 const int escapeitems
[] = { PICK_AXE
,
4289 RIN_TELEPORTATION
};
4290 struct opvar
*ov2
= selection_opvar((char *) 0), *ov3
;
4294 selection_floodfill(ov2
, nx
, ny
, TRUE
);
4295 ov3
= opvar_clone(ov2
);
4297 /* try to make a secret door */
4298 while (selection_rndcoord(ov3
, &x
, &y
, TRUE
)) {
4299 if (isok(x
+1, y
) && !selection_getpoint(x
+1, y
, ov
)
4300 && IS_WALL(levl
[x
+1][y
].typ
)
4301 && isok(x
+2, y
) && selection_getpoint(x
+2, y
, ov
)
4302 && ACCESSIBLE(levl
[x
+2][y
].typ
)) {
4303 levl
[x
+1][y
].typ
= SDOOR
;
4306 if (isok(x
-1, y
) && !selection_getpoint(x
-1, y
, ov
)
4307 && IS_WALL(levl
[x
-1][y
].typ
)
4308 && isok(x
-2, y
) && selection_getpoint(x
-2, y
, ov
)
4309 && ACCESSIBLE(levl
[x
-2][y
].typ
)) {
4310 levl
[x
-1][y
].typ
= SDOOR
;
4313 if (isok(x
, y
+1) && !selection_getpoint(x
, y
+1, ov
)
4314 && IS_WALL(levl
[x
][y
+1].typ
)
4315 && isok(x
, y
+2) && selection_getpoint(x
, y
+2, ov
)
4316 && ACCESSIBLE(levl
[x
][y
+2].typ
)) {
4317 levl
[x
][y
+1].typ
= SDOOR
;
4320 if (isok(x
, y
-1) && !selection_getpoint(x
, y
-1, ov
)
4321 && IS_WALL(levl
[x
][y
-1].typ
)
4322 && isok(x
, y
-2) && selection_getpoint(x
, y
-2, ov
)
4323 && ACCESSIBLE(levl
[x
][y
-2].typ
)) {
4324 levl
[x
][y
-1].typ
= SDOOR
;
4329 /* try to make a hole or a trapdoor */
4330 if (Can_fall_thru(&u
.uz
)) {
4332 ov3
= opvar_clone(ov2
);
4333 while (selection_rndcoord(ov3
, &x
, &y
, TRUE
)) {
4334 if (maketrap(x
,y
, rn2(2) ? HOLE
: TRAPDOOR
))
4339 /* generate one of the escape items */
4340 if (selection_rndcoord(ov2
, &x
, &y
, FALSE
)) {
4341 mksobj_at(escapeitems
[rn2(SIZE(escapeitems
))], x
, y
, TRUE
, FALSE
);
4355 static const char nhFunc
[] = "ensure_way_out";
4356 struct opvar
*ov
= selection_opvar((char *) 0);
4357 struct trap
*ttmp
= ftrap
;
4361 set_selection_floodfillchk(floodfillchk_match_accessible
);
4363 if (xupstair
&& !selection_getpoint(xupstair
, yupstair
, ov
))
4364 selection_floodfill(ov
, xupstair
, yupstair
, TRUE
);
4365 if (xdnstair
&& !selection_getpoint(xdnstair
, ydnstair
, ov
))
4366 selection_floodfill(ov
, xdnstair
, ydnstair
, TRUE
);
4367 if (xupladder
&& !selection_getpoint(xupladder
, yupladder
, ov
))
4368 selection_floodfill(ov
, xupladder
, yupladder
, TRUE
);
4369 if (xdnladder
&& !selection_getpoint(xdnladder
, ydnladder
, ov
))
4370 selection_floodfill(ov
, xdnladder
, ydnladder
, TRUE
);
4373 if ((ttmp
->ttyp
== MAGIC_PORTAL
|| ttmp
->ttyp
== VIBRATING_SQUARE
4374 || ttmp
->ttyp
== HOLE
|| ttmp
->ttyp
== TRAPDOOR
)
4375 && !selection_getpoint(ttmp
->tx
, ttmp
->ty
, ov
))
4376 selection_floodfill(ov
, ttmp
->tx
, ttmp
->ty
, TRUE
);
4382 for (x
= 0; x
< COLNO
; x
++)
4383 for (y
= 0; y
< ROWNO
; y
++)
4384 if (ACCESSIBLE(levl
[x
][y
].typ
)
4385 && !selection_getpoint(x
, y
, ov
)) {
4386 if (generate_way_out_method(x
,y
, ov
))
4387 selection_floodfill(ov
, x
,y
, TRUE
);
4397 spo_levregion(coder
)
4398 struct sp_coder
*coder
;
4400 static const char nhFunc
[] = "spo_levregion";
4401 struct opvar
*rname
, *padding
, *rtype
, *del_islev
, *dy2
, *dx2
, *dy1
, *dx1
,
4402 *in_islev
, *iy2
, *ix2
, *iy1
, *ix1
;
4404 lev_region
*tmplregion
;
4406 if (!OV_pop_s(rname
) || !OV_pop_i(padding
) || !OV_pop_i(rtype
)
4407 || !OV_pop_i(del_islev
) || !OV_pop_i(dy2
) || !OV_pop_i(dx2
)
4408 || !OV_pop_i(dy1
) || !OV_pop_i(dx1
) || !OV_pop_i(in_islev
)
4409 || !OV_pop_i(iy2
) || !OV_pop_i(ix2
) || !OV_pop_i(iy1
)
4413 tmplregion
= (lev_region
*) alloc(sizeof(lev_region
));
4415 tmplregion
->inarea
.x1
= OV_i(ix1
);
4416 tmplregion
->inarea
.y1
= OV_i(iy1
);
4417 tmplregion
->inarea
.x2
= OV_i(ix2
);
4418 tmplregion
->inarea
.y2
= OV_i(iy2
);
4420 tmplregion
->delarea
.x1
= OV_i(dx1
);
4421 tmplregion
->delarea
.y1
= OV_i(dy1
);
4422 tmplregion
->delarea
.x2
= OV_i(dx2
);
4423 tmplregion
->delarea
.y2
= OV_i(dy2
);
4425 tmplregion
->in_islev
= OV_i(in_islev
);
4426 tmplregion
->del_islev
= OV_i(del_islev
);
4427 tmplregion
->rtype
= OV_i(rtype
);
4428 tmplregion
->padding
= OV_i(padding
);
4429 tmplregion
->rname
.str
= dupstr(OV_s(rname
));
4431 if (!tmplregion
->in_islev
) {
4432 get_location(&tmplregion
->inarea
.x1
, &tmplregion
->inarea
.y1
, ANY_LOC
,
4433 (struct mkroom
*) 0);
4434 get_location(&tmplregion
->inarea
.x2
, &tmplregion
->inarea
.y2
, ANY_LOC
,
4435 (struct mkroom
*) 0);
4438 if (!tmplregion
->del_islev
) {
4439 get_location(&tmplregion
->delarea
.x1
, &tmplregion
->delarea
.y1
,
4440 ANY_LOC
, (struct mkroom
*) 0);
4441 get_location(&tmplregion
->delarea
.x2
, &tmplregion
->delarea
.y2
,
4442 ANY_LOC
, (struct mkroom
*) 0);
4445 /* realloc the lregion space to add the new one */
4446 lev_region
*newl
= (lev_region
*) alloc(
4447 sizeof(lev_region
) * (unsigned) (1 + num_lregions
));
4449 (void) memcpy((genericptr_t
) (newl
), (genericptr_t
) lregions
,
4450 sizeof(lev_region
) * num_lregions
);
4456 lregions
= (lev_region
*) alloc(sizeof(lev_region
));
4458 (void) memcpy(&lregions
[num_lregions
- 1], tmplregion
,
4459 sizeof(lev_region
));
4472 opvar_free(del_islev
);
4473 opvar_free(in_islev
);
4476 opvar_free(padding
);
4481 struct sp_coder
*coder
;
4483 static const char nhFunc
[] = "spo_region";
4484 struct opvar
*rtype
, *rlit
, *rflags
, *area
;
4485 xchar dx1
, dy1
, dx2
, dy2
;
4486 register struct mkroom
*troom
;
4487 boolean prefilled
, room_not_needed
, irregular
, joined
;
4489 if (!OV_pop_i(rflags
) || !OV_pop_i(rtype
) || !OV_pop_i(rlit
)
4493 prefilled
= !(OV_i(rflags
) & (1 << 0));
4494 irregular
= (OV_i(rflags
) & (1 << 1));
4495 joined
= !(OV_i(rflags
) & (1 << 2));
4497 if (OV_i(rtype
) > MAXRTYPE
) {
4498 OV_i(rtype
) -= MAXRTYPE
+ 1;
4505 (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? TRUE
: FALSE
;
4507 dx1
= SP_REGION_X1(OV_i(area
));
4508 dy1
= SP_REGION_Y1(OV_i(area
));
4509 dx2
= SP_REGION_X2(OV_i(area
));
4510 dy2
= SP_REGION_Y2(OV_i(area
));
4512 get_location(&dx1
, &dy1
, ANY_LOC
, (struct mkroom
*) 0);
4513 get_location(&dx2
, &dy2
, ANY_LOC
, (struct mkroom
*) 0);
4515 /* for an ordinary room, `prefilled' is a flag to force
4516 an actual room to be created (such rooms are used to
4517 control placement of migrating monster arrivals) */
4518 room_not_needed
= (OV_i(rtype
) == OROOM
&& !irregular
&& !prefilled
);
4519 if (room_not_needed
|| nroom
>= MAXNROFROOMS
) {
4521 if (!room_not_needed
)
4522 impossible("Too many rooms on new level!");
4523 tmpregion
.rlit
= OV_i(rlit
);
4528 light_region(&tmpregion
);
4538 troom
= &rooms
[nroom
];
4540 /* mark rooms that must be filled, but do it later */
4541 if (OV_i(rtype
) != OROOM
)
4542 troom
->needfill
= (prefilled
? 2 : 1);
4544 troom
->needjoining
= joined
;
4547 min_rx
= max_rx
= dx1
;
4548 min_ry
= max_ry
= dy1
;
4549 smeq
[nroom
] = nroom
;
4550 flood_fill_rm(dx1
, dy1
, nroom
+ ROOMOFFSET
, OV_i(rlit
), TRUE
);
4551 add_room(min_rx
, min_ry
, max_rx
, max_ry
, FALSE
, OV_i(rtype
), TRUE
);
4552 troom
->rlit
= OV_i(rlit
);
4553 troom
->irregular
= TRUE
;
4555 add_room(dx1
, dy1
, dx2
, dy2
, OV_i(rlit
), OV_i(rtype
), TRUE
);
4556 #ifdef SPECIALIZATION
4557 topologize(troom
, FALSE
); /* set roomno */
4559 topologize(troom
); /* set roomno */
4563 if (!room_not_needed
) {
4564 if (coder
->n_subroom
> 1)
4565 impossible("region as subroom");
4567 coder
->tmproomlist
[coder
->n_subroom
] = troom
;
4568 coder
->failed_room
[coder
->n_subroom
] = FALSE
;
4580 spo_drawbridge(coder
)
4581 struct sp_coder
*coder
;
4583 static const char nhFunc
[] = "spo_drawbridge";
4585 struct opvar
*dir
, *db_open
, *dcoord
;
4587 if (!OV_pop_i(dir
) || !OV_pop_i(db_open
) || !OV_pop_c(dcoord
))
4590 get_location_coord(&x
, &y
, DRY
| WET
| HOT
, coder
->croom
, OV_i(dcoord
));
4591 if (!create_drawbridge(x
, y
, OV_i(dir
), OV_i(db_open
)))
4592 impossible("Cannot create drawbridge.");
4593 SpLev_Map
[x
][y
] = 1;
4596 opvar_free(db_open
);
4602 struct sp_coder
*coder
;
4604 static const char nhFunc
[] = "spo_mazewalk";
4606 struct opvar
*ftyp
, *fstocked
, *fdir
, *mcoord
;
4609 if (!OV_pop_i(ftyp
) || !OV_pop_i(fstocked
) || !OV_pop_i(fdir
)
4610 || !OV_pop_c(mcoord
))
4615 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(mcoord
));
4619 if (OV_i(ftyp
) < 1) {
4620 OV_i(ftyp
) = level
.flags
.corrmaze
? CORR
: ROOM
;
4623 /* don't use move() - it doesn't use W_NORTH, etc. */
4638 impossible("spo_mazewalk: Bad MAZEWALK direction");
4641 if (!IS_DOOR(levl
[x
][y
].typ
)) {
4642 levl
[x
][y
].typ
= OV_i(ftyp
);
4643 levl
[x
][y
].flags
= 0;
4647 * We must be sure that the parity of the coordinates for
4648 * walkfrom() is odd. But we must also take into account
4649 * what direction was chosen.
4657 /* no need for IS_DOOR check; out of map bounds */
4658 levl
[x
][y
].typ
= OV_i(ftyp
);
4659 levl
[x
][y
].flags
= 0;
4669 walkfrom(x
, y
, OV_i(ftyp
));
4675 opvar_free(fstocked
);
4680 spo_wall_property(coder
)
4681 struct sp_coder
*coder
;
4683 static const char nhFunc
[] = "spo_wall_property";
4685 xchar dx1
, dy1
, dx2
, dy2
;
4686 int wprop
= (coder
->opcode
== SPO_NON_DIGGABLE
)
4693 dx1
= SP_REGION_X1(OV_i(r
));
4694 dy1
= SP_REGION_Y1(OV_i(r
));
4695 dx2
= SP_REGION_X2(OV_i(r
));
4696 dy2
= SP_REGION_Y2(OV_i(r
));
4698 get_location(&dx1
, &dy1
, ANY_LOC
, (struct mkroom
*) 0);
4699 get_location(&dx2
, &dy2
, ANY_LOC
, (struct mkroom
*) 0);
4701 set_wall_property(dx1
, dy1
, dx2
, dy2
, wprop
);
4707 spo_room_door(coder
)
4708 struct sp_coder
*coder
;
4710 static const char nhFunc
[] = "spo_room_door";
4711 struct opvar
*wall
, *secret
, *mask
, *pos
;
4714 if (!OV_pop_i(wall
) || !OV_pop_i(secret
) || !OV_pop_i(mask
)
4715 || !OV_pop_i(pos
) || !coder
->croom
)
4718 tmpd
.secret
= OV_i(secret
);
4719 tmpd
.mask
= OV_i(mask
);
4720 tmpd
.pos
= OV_i(pos
);
4721 tmpd
.wall
= OV_i(wall
);
4723 create_door(&tmpd
, coder
->croom
);
4733 sel_set_wallify(x
, y
, arg
)
4735 genericptr_t arg UNUSED
;
4737 wallify_map(x
, y
, x
, y
);
4742 struct sp_coder
*coder
;
4744 static const char nhFunc
[] = "spo_wallify";
4745 struct opvar
*typ
, *r
;
4746 int dx1
, dy1
, dx2
, dy2
;
4750 switch (OV_i(typ
)) {
4755 dx1
= (xchar
) SP_REGION_X1(OV_i(r
));
4756 dy1
= (xchar
) SP_REGION_Y1(OV_i(r
));
4757 dx2
= (xchar
) SP_REGION_X2(OV_i(r
));
4758 dy2
= (xchar
) SP_REGION_Y2(OV_i(r
));
4759 wallify_map(dx1
< 0 ? (xstart
- 1) : dx1
,
4760 dy1
< 0 ? (ystart
- 1) : dy1
,
4761 dx2
< 0 ? (xstart
+ xsize
+ 1) : dx2
,
4762 dy2
< 0 ? (ystart
+ ysize
+ 1) : dy2
);
4765 if (!OV_pop_typ(r
, SPOVAR_SEL
))
4767 selection_iterate(r
, sel_set_wallify
, NULL
);
4776 struct sp_coder
*coder
;
4778 static const char nhFunc
[] = "spo_map";
4779 mazepart tmpmazepart
;
4780 struct opvar
*mpxs
, *mpys
, *mpmap
, *mpa
, *mpkeepr
, *mpzalign
;
4781 xchar halign
, valign
;
4782 xchar tmpxstart
, tmpystart
, tmpxsize
, tmpysize
;
4785 if (!OV_pop_i(mpxs
) || !OV_pop_i(mpys
) || !OV_pop_s(mpmap
)
4786 || !OV_pop_i(mpkeepr
) || !OV_pop_i(mpzalign
) || !OV_pop_c(mpa
))
4789 tmpmazepart
.xsize
= OV_i(mpxs
);
4790 tmpmazepart
.ysize
= OV_i(mpys
);
4791 tmpmazepart
.zaligntyp
= OV_i(mpzalign
);
4793 upc
= get_unpacked_coord(OV_i(mpa
), ANY_LOC
);
4794 tmpmazepart
.halign
= upc
.x
;
4795 tmpmazepart
.valign
= upc
.y
;
4802 halign
= tmpmazepart
.halign
;
4803 valign
= tmpmazepart
.valign
;
4804 xsize
= tmpmazepart
.xsize
;
4805 ysize
= tmpmazepart
.ysize
;
4806 switch (tmpmazepart
.zaligntyp
) {
4811 switch ((int) halign
) {
4813 xstart
= splev_init_present
? 1 : 3;
4816 xstart
= 2 + ((x_maze_max
- 2 - xsize
) / 4);
4819 xstart
= 2 + ((x_maze_max
- 2 - xsize
) / 2);
4822 xstart
= 2 + ((x_maze_max
- 2 - xsize
) * 3 / 4);
4825 xstart
= x_maze_max
- xsize
- 1;
4828 switch ((int) valign
) {
4833 ystart
= 2 + ((y_maze_max
- 2 - ysize
) / 2);
4836 ystart
= y_maze_max
- ysize
- 1;
4845 if (!coder
->croom
) {
4848 xsize
= COLNO
- 1 - tmpmazepart
.xsize
;
4849 ysize
= ROWNO
- tmpmazepart
.ysize
;
4851 get_location_coord(&halign
, &valign
, ANY_LOC
, coder
->croom
,
4853 xsize
= tmpmazepart
.xsize
;
4854 ysize
= tmpmazepart
.ysize
;
4859 if (ystart
< 0 || ystart
+ ysize
> ROWNO
) {
4860 /* try to move the start a bit */
4861 ystart
+= (ystart
> 0) ? -2 : 2;
4864 if (ystart
< 0 || ystart
+ ysize
> ROWNO
)
4865 panic("reading special level with ysize too large");
4867 if (xsize
<= 1 && ysize
<= 1) {
4876 for (y
= ystart
; y
< ystart
+ ysize
; y
++)
4877 for (x
= xstart
; x
< xstart
+ xsize
; x
++) {
4878 mptyp
= (mpmap
->vardata
.str
[(y
- ystart
) * xsize
4879 + (x
- xstart
)] - 1);
4880 if (mptyp
>= MAX_TYPE
)
4882 levl
[x
][y
].typ
= mptyp
;
4883 levl
[x
][y
].lit
= FALSE
;
4884 /* clear out levl: load_common_data may set them */
4885 levl
[x
][y
].flags
= 0;
4886 levl
[x
][y
].horizontal
= 0;
4887 levl
[x
][y
].roomno
= 0;
4888 levl
[x
][y
].edge
= 0;
4889 SpLev_Map
[x
][y
] = 1;
4891 * Set secret doors to closed (why not trapped too?). Set
4892 * the horizontal bit.
4894 if (levl
[x
][y
].typ
== SDOOR
|| IS_DOOR(levl
[x
][y
].typ
)) {
4895 if (levl
[x
][y
].typ
== SDOOR
)
4896 levl
[x
][y
].doormask
= D_CLOSED
;
4898 * If there is a wall to the left that connects to a
4899 * (secret) door, then it is horizontal. This does
4900 * not allow (secret) doors to be corners of rooms.
4902 if (x
!= xstart
&& (IS_WALL(levl
[x
- 1][y
].typ
)
4903 || levl
[x
- 1][y
].horizontal
))
4904 levl
[x
][y
].horizontal
= 1;
4905 } else if (levl
[x
][y
].typ
== HWALL
4906 || levl
[x
][y
].typ
== IRONBARS
)
4907 levl
[x
][y
].horizontal
= 1;
4908 else if (levl
[x
][y
].typ
== LAVAPOOL
)
4910 else if (splev_init_present
&& levl
[x
][y
].typ
== ICE
)
4911 levl
[x
][y
].icedpool
= icedpools
? ICED_POOL
: ICED_MOAT
;
4913 if (coder
->lvl_is_joined
)
4914 remove_rooms(xstart
, ystart
, xstart
+ xsize
, ystart
+ ysize
);
4916 if (!OV_i(mpkeepr
)) {
4927 opvar_free(mpkeepr
);
4928 opvar_free(mpzalign
);
4933 struct sp_coder
*coder
;
4936 static const char nhFunc
[] = "spo_jmp";
4940 if (!OV_pop_i(tmpa
))
4942 a
= sp_code_jmpaddr(coder
->frame
->n_opcode
, (OV_i(tmpa
) - 1));
4943 if ((a
>= 0) && (a
< lvl
->n_opcodes
) && (a
!= coder
->frame
->n_opcode
))
4944 coder
->frame
->n_opcode
= a
;
4949 spo_conditional_jump(coder
, lvl
)
4950 struct sp_coder
*coder
;
4953 static const char nhFunc
[] = "spo_conditional_jump";
4954 struct opvar
*oa
, *oc
;
4958 if (!OV_pop_i(oa
) || !OV_pop_i(oc
))
4961 a
= sp_code_jmpaddr(coder
->frame
->n_opcode
, (OV_i(oa
) - 1));
4964 switch (coder
->opcode
) {
4966 impossible("spo_conditional_jump: illegal opcode");
4969 test
= (c
& SP_CPUFLAG_LT
);
4972 test
= (c
& (SP_CPUFLAG_LT
| SP_CPUFLAG_EQ
));
4975 test
= (c
& SP_CPUFLAG_GT
);
4978 test
= (c
& (SP_CPUFLAG_GT
| SP_CPUFLAG_EQ
));
4981 test
= (c
& SP_CPUFLAG_EQ
);
4984 test
= (c
& ~SP_CPUFLAG_EQ
);
4988 if ((test
) && (a
>= 0) && (a
< lvl
->n_opcodes
)
4989 && (a
!= coder
->frame
->n_opcode
))
4990 coder
->frame
->n_opcode
= a
;
4998 struct sp_coder
*coder
;
5000 static const char nhFunc
[] = "spo_var_init";
5001 struct opvar
*vname
;
5002 struct opvar
*arraylen
;
5003 struct opvar
*vvalue
;
5004 struct splev_var
*tmpvar
;
5005 struct splev_var
*tmp2
;
5011 if (!vname
|| !arraylen
)
5012 panic("no values for SPO_VAR_INIT");
5014 tmpvar
= opvar_var_defined(coder
, OV_s(vname
));
5017 /* variable redefinition */
5018 if (OV_i(arraylen
) < 0) {
5020 if (tmpvar
->array_len
) {
5021 idx
= tmpvar
->array_len
;
5023 opvar_free(tmpvar
->data
.arrayvalues
[idx
]);
5025 Free(tmpvar
->data
.arrayvalues
);
5027 opvar_free(tmpvar
->data
.value
);
5029 tmpvar
->data
.arrayvalues
= NULL
;
5031 } else if (OV_i(arraylen
)) {
5032 /* redefined array */
5033 idx
= tmpvar
->array_len
;
5035 opvar_free(tmpvar
->data
.arrayvalues
[idx
]);
5037 Free(tmpvar
->data
.arrayvalues
);
5038 tmpvar
->data
.arrayvalues
= NULL
;
5039 goto create_new_array
;
5041 /* redefined single value */
5043 if (tmpvar
->svtyp
!= vvalue
->spovartyp
)
5044 panic("redefining variable as different type");
5045 opvar_free(tmpvar
->data
.value
);
5046 tmpvar
->data
.value
= vvalue
;
5047 tmpvar
->array_len
= 0;
5050 /* new variable definition */
5051 tmpvar
= (struct splev_var
*) alloc(sizeof(struct splev_var
));
5052 tmpvar
->next
= coder
->frame
->variables
;
5053 tmpvar
->name
= dupstr(OV_s(vname
));
5054 coder
->frame
->variables
= tmpvar
;
5056 if (OV_i(arraylen
) < 0) {
5060 tmp2
= opvar_var_defined(coder
, OV_s(vvalue
));
5062 panic("no copyable var");
5063 tmpvar
->svtyp
= tmp2
->svtyp
;
5064 tmpvar
->array_len
= tmp2
->array_len
;
5065 if (tmpvar
->array_len
) {
5066 idx
= tmpvar
->array_len
;
5067 tmpvar
->data
.arrayvalues
=
5068 (struct opvar
**) alloc(sizeof(struct opvar
*) * idx
);
5070 tmpvar
->data
.arrayvalues
[idx
] =
5071 opvar_clone(tmp2
->data
.arrayvalues
[idx
]);
5074 tmpvar
->data
.value
= opvar_clone(tmp2
->data
.value
);
5077 } else if (OV_i(arraylen
)) {
5080 idx
= OV_i(arraylen
);
5081 tmpvar
->array_len
= idx
;
5082 tmpvar
->data
.arrayvalues
=
5083 (struct opvar
**) alloc(sizeof(struct opvar
*) * idx
);
5087 panic("no value for arrayvariable");
5088 tmpvar
->data
.arrayvalues
[idx
] = vvalue
;
5090 tmpvar
->svtyp
= SPOVAR_ARRAY
;
5092 /* new single value */
5095 panic("no value for variable");
5096 tmpvar
->svtyp
= OV_typ(vvalue
);
5097 tmpvar
->data
.value
= vvalue
;
5098 tmpvar
->array_len
= 0;
5103 opvar_free(arraylen
);
5109 opvar_array_length(coder
)
5110 struct sp_coder
*coder
;
5112 static const char nhFunc
[] = "opvar_array_length";
5113 struct opvar
*vname
;
5114 struct splev_var
*tmp
;
5120 vname
= splev_stack_pop(coder
->stack
);
5123 if (vname
->spovartyp
!= SPOVAR_VARIABLE
)
5126 tmp
= coder
->frame
->variables
;
5128 if (!strcmp(tmp
->name
, OV_s(vname
))) {
5129 if ((tmp
->svtyp
& SPOVAR_ARRAY
)) {
5130 len
= tmp
->array_len
;
5146 spo_shuffle_array(coder
)
5147 struct sp_coder
*coder
;
5149 static const char nhFunc
[] = "spo_shuffle_array";
5150 struct opvar
*vname
;
5151 struct splev_var
*tmp
;
5155 if (!OV_pop_s(vname
))
5158 tmp
= opvar_var_defined(coder
, OV_s(vname
));
5159 if (!tmp
|| (tmp
->array_len
< 1)) {
5163 for (i
= tmp
->array_len
- 1; i
> 0; i
--) {
5164 if ((j
= rn2(i
+ 1)) == i
)
5166 tmp2
= tmp
->data
.arrayvalues
[j
];
5167 tmp
->data
.arrayvalues
[j
] = tmp
->data
.arrayvalues
[i
];
5168 tmp
->data
.arrayvalues
[i
] = tmp2
;
5174 /* Special level coder, creates the special level from the sp_lev codes.
5175 * Does not free the allocated memory.
5181 static const char nhFunc
[] = "sp_level_coder";
5182 unsigned long exec_opcodes
= 0;
5184 long room_stack
= 0;
5185 unsigned long max_execution
= SPCODER_MAX_RUNTIME
;
5186 struct sp_coder
*coder
=
5187 (struct sp_coder
*) alloc(sizeof(struct sp_coder
));
5189 coder
->frame
= frame_new(0);
5190 coder
->stack
= NULL
;
5191 coder
->premapped
= FALSE
;
5192 coder
->solidify
= FALSE
;
5193 coder
->check_inaccessibles
= FALSE
;
5194 coder
->croom
= NULL
;
5195 coder
->n_subroom
= 1;
5196 coder
->exit_script
= FALSE
;
5197 coder
->lvl_is_joined
= 0;
5199 splev_init_present
= FALSE
;
5203 char *met
= nh_getenv("SPCODER_MAX_RUNTIME");
5204 if (met
&& met
[0] == '1')
5205 max_execution
= (1 << 30) - 1;
5208 for (tmpi
= 0; tmpi
<= MAX_NESTED_ROOMS
; tmpi
++) {
5209 coder
->tmproomlist
[tmpi
] = (struct mkroom
*) 0;
5210 coder
->failed_room
[tmpi
] = FALSE
;
5213 shuffle_alignments();
5215 for (tmpi
= 0; tmpi
< MAX_CONTAINMENT
; tmpi
++)
5216 container_obj
[tmpi
] = NULL
;
5219 invent_carrying_monster
= NULL
;
5221 (void) memset((genericptr_t
) &SpLev_Map
[0][0], 0, sizeof SpLev_Map
);
5223 level
.flags
.is_maze_lev
= 0;
5230 while (coder
->frame
->n_opcode
< lvl
->n_opcodes
&& !coder
->exit_script
) {
5231 coder
->opcode
= lvl
->opcodes
[coder
->frame
->n_opcode
].opcode
;
5232 coder
->opdat
= lvl
->opcodes
[coder
->frame
->n_opcode
].opdat
;
5234 coder
->stack
= coder
->frame
->stack
;
5236 if (exec_opcodes
++ > max_execution
) {
5237 impossible("Level script is taking too much time, stopping.");
5238 coder
->exit_script
= TRUE
;
5241 if (coder
->failed_room
[coder
->n_subroom
- 1]
5242 && coder
->opcode
!= SPO_ENDROOM
&& coder
->opcode
!= SPO_ROOM
5243 && coder
->opcode
!= SPO_SUBROOM
)
5246 coder
->croom
= coder
->tmproomlist
[coder
->n_subroom
- 1];
5248 switch (coder
->opcode
) {
5252 coder
->exit_script
= TRUE
;
5254 case SPO_FRAME_PUSH
:
5255 spo_frame_push(coder
);
5258 spo_frame_pop(coder
);
5266 case SPO_END_MONINVENT
:
5267 spo_end_moninvent(coder
);
5269 case SPO_POP_CONTAINER
:
5270 spo_pop_container(coder
);
5273 struct opvar
*ov
= splev_stack_pop(coder
->stack
);
5279 splev_stack_push(coder
->stack
, opvar_clone(coder
->opdat
));
5290 case SPO_LEVEL_FLAGS
:
5291 spo_level_flags(coder
);
5294 spo_initlevel(coder
);
5297 spo_engraving(coder
);
5299 case SPO_MINERALIZE
:
5300 spo_mineralize(coder
);
5304 if (!coder
->failed_room
[coder
->n_subroom
- 1]) {
5310 if (coder
->failed_room
[coder
->n_subroom
- 1]) {
5346 spo_corridor(coder
);
5351 case SPO_REPLACETERRAIN
:
5352 spo_replace_terrain(coder
);
5355 spo_levregion(coder
);
5360 case SPO_DRAWBRIDGE
:
5361 spo_drawbridge(coder
);
5364 spo_mazewalk(coder
);
5366 case SPO_NON_PASSWALL
:
5367 case SPO_NON_DIGGABLE
:
5368 spo_wall_property(coder
);
5371 spo_room_door(coder
);
5377 struct opvar
*a
= splev_stack_pop(coder
->stack
);
5379 splev_stack_push(coder
->stack
, opvar_clone(a
));
5380 splev_stack_push(coder
->stack
, opvar_clone(a
));
5390 splev_stack_push(coder
->stack
, a
);
5399 splev_stack_push(coder
->stack
, a
);
5402 case SPO_MATH_SIGN
: {
5407 OV_i(a
) = ((OV_i(a
) < 0) ? -1 : ((OV_i(a
) > 0) ? 1 : 0));
5408 splev_stack_push(coder
->stack
, a
);
5411 case SPO_MATH_ADD
: {
5412 struct opvar
*a
, *b
;
5414 if (!OV_pop(b
) || !OV_pop(a
))
5416 if (OV_typ(b
) == OV_typ(a
)) {
5417 if (OV_typ(a
) == SPOVAR_INT
) {
5418 OV_i(a
) = OV_i(a
) + OV_i(b
);
5419 splev_stack_push(coder
->stack
, a
);
5421 } else if (OV_typ(a
) == SPOVAR_STRING
) {
5423 char *tmpbuf
= (char *) alloc(strlen(OV_s(a
))
5424 + strlen(OV_s(b
)) + 1);
5426 (void) sprintf(tmpbuf
, "%s%s", OV_s(a
), OV_s(b
));
5427 c
= opvar_new_str(tmpbuf
);
5428 splev_stack_push(coder
->stack
, c
);
5433 splev_stack_push(coder
->stack
, a
);
5435 impossible("adding weird types");
5438 splev_stack_push(coder
->stack
, a
);
5440 impossible("adding different types");
5444 case SPO_MATH_SUB
: {
5445 struct opvar
*a
, *b
;
5447 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5449 OV_i(a
) = OV_i(a
) - OV_i(b
);
5450 splev_stack_push(coder
->stack
, a
);
5454 case SPO_MATH_MUL
: {
5455 struct opvar
*a
, *b
;
5457 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5459 OV_i(a
) = OV_i(a
) * OV_i(b
);
5460 splev_stack_push(coder
->stack
, a
);
5464 case SPO_MATH_DIV
: {
5465 struct opvar
*a
, *b
;
5467 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5470 OV_i(a
) = OV_i(a
) / OV_i(b
);
5474 splev_stack_push(coder
->stack
, a
);
5478 case SPO_MATH_MOD
: {
5479 struct opvar
*a
, *b
;
5481 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5484 OV_i(a
) = OV_i(a
) % OV_i(b
);
5488 splev_stack_push(coder
->stack
, a
);
5501 impossible("spo_cmp: no values in stack");
5504 if (OV_typ(a
) != OV_typ(b
)) {
5505 impossible("spo_cmp: trying to compare differing datatypes");
5508 switch (OV_typ(a
)) {
5511 case SPOVAR_MAPCHAR
:
5515 if (OV_i(b
) > OV_i(a
))
5516 val
|= SP_CPUFLAG_LT
;
5517 if (OV_i(b
) < OV_i(a
))
5518 val
|= SP_CPUFLAG_GT
;
5519 if (OV_i(b
) == OV_i(a
))
5520 val
|= SP_CPUFLAG_EQ
;
5521 c
= opvar_new_int(val
);
5524 c
= opvar_new_int(!strcmp(OV_s(b
), OV_s(a
))
5529 c
= opvar_new_int(0);
5532 splev_stack_push(coder
->stack
, c
);
5538 spo_jmp(coder
, lvl
);
5546 spo_conditional_jump(coder
, lvl
);
5552 if (!OV_pop_i(tmpv
))
5554 t
= opvar_new_int((OV_i(tmpv
) > 1) ? rn2(OV_i(tmpv
)) : 0);
5555 splev_stack_push(coder
->stack
, t
);
5560 struct opvar
*a
, *b
, *t
;
5562 if (!OV_pop_i(b
) || !OV_pop_i(a
))
5568 t
= opvar_new_int(d(OV_i(a
), OV_i(b
)));
5569 splev_stack_push(coder
->stack
, t
);
5578 spo_var_init(coder
);
5580 case SPO_SHUFFLE_ARRAY
:
5581 spo_shuffle_array(coder
);
5583 case SPO_SEL_ADD
: /* actually, logical or */
5585 struct opvar
*sel1
, *sel2
, *pt
;
5587 if (!OV_pop_typ(sel1
, SPOVAR_SEL
))
5588 panic("no sel1 for add");
5589 if (!OV_pop_typ(sel2
, SPOVAR_SEL
))
5590 panic("no sel2 for add");
5591 pt
= selection_logical_oper(sel1
, sel2
, '|');
5594 splev_stack_push(coder
->stack
, pt
);
5597 case SPO_SEL_COMPLEMENT
: {
5598 struct opvar
*sel
, *pt
;
5600 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
5601 panic("no sel for not");
5602 pt
= selection_not(sel
);
5604 splev_stack_push(coder
->stack
, pt
);
5607 case SPO_SEL_FILTER
: /* sorta like logical and */
5609 struct opvar
*filtertype
;
5611 if (!OV_pop_i(filtertype
))
5612 panic("no sel filter type");
5613 switch (OV_i(filtertype
)) {
5614 case SPOFILTER_PERCENT
: {
5615 struct opvar
*tmp1
, *sel
;
5617 if (!OV_pop_i(tmp1
))
5618 panic("no sel filter percent");
5619 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
5620 panic("no sel filter");
5621 selection_filter_percent(sel
, OV_i(tmp1
));
5622 splev_stack_push(coder
->stack
, sel
);
5626 case SPOFILTER_SELECTION
: /* logical and */
5628 struct opvar
*pt
, *sel1
, *sel2
;
5630 if (!OV_pop_typ(sel1
, SPOVAR_SEL
))
5631 panic("no sel filter sel1");
5632 if (!OV_pop_typ(sel2
, SPOVAR_SEL
))
5633 panic("no sel filter sel2");
5634 pt
= selection_logical_oper(sel1
, sel2
, '&');
5635 splev_stack_push(coder
->stack
, pt
);
5640 case SPOFILTER_MAPCHAR
: {
5641 struct opvar
*pt
, *tmp1
, *sel
;
5643 if (!OV_pop_typ(sel
, SPOVAR_SEL
))
5644 panic("no sel filter");
5645 if (!OV_pop_typ(tmp1
, SPOVAR_MAPCHAR
))
5646 panic("no sel filter mapchar");
5647 pt
= selection_filter_mapchar(sel
, tmp1
);
5648 splev_stack_push(coder
->stack
, pt
);
5654 panic("unknown sel filter type");
5656 opvar_free(filtertype
);
5659 case SPO_SEL_POINT
: {
5661 struct opvar
*pt
= selection_opvar((char *) 0);
5665 panic("no ter sel coord");
5666 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5667 selection_setpoint(x
, y
, pt
, 1);
5668 splev_stack_push(coder
->stack
, pt
);
5673 case SPO_SEL_FILLRECT
: {
5674 struct opvar
*tmp
, *pt
= selection_opvar((char *) 0);
5675 schar x
, y
, x1
, y1
, x2
, y2
;
5678 panic("no ter sel region");
5679 x1
= min(SP_REGION_X1(OV_i(tmp
)), SP_REGION_X2(OV_i(tmp
)));
5680 y1
= min(SP_REGION_Y1(OV_i(tmp
)), SP_REGION_Y2(OV_i(tmp
)));
5681 x2
= max(SP_REGION_X1(OV_i(tmp
)), SP_REGION_X2(OV_i(tmp
)));
5682 y2
= max(SP_REGION_Y1(OV_i(tmp
)), SP_REGION_Y2(OV_i(tmp
)));
5683 get_location(&x1
, &y1
, ANY_LOC
, coder
->croom
);
5684 get_location(&x2
, &y2
, ANY_LOC
, coder
->croom
);
5685 x1
= (x1
< 0) ? 0 : x1
;
5686 y1
= (y1
< 0) ? 0 : y1
;
5687 x2
= (x2
>= COLNO
) ? COLNO
- 1 : x2
;
5688 y2
= (y2
>= ROWNO
) ? ROWNO
- 1 : y2
;
5689 if (coder
->opcode
== SPO_SEL_RECT
) {
5690 for (x
= x1
; x
<= x2
; x
++) {
5691 selection_setpoint(x
, y1
, pt
, 1);
5692 selection_setpoint(x
, y2
, pt
, 1);
5694 for (y
= y1
; y
<= y2
; y
++) {
5695 selection_setpoint(x1
, y
, pt
, 1);
5696 selection_setpoint(x2
, y
, pt
, 1);
5699 for (x
= x1
; x
<= x2
; x
++)
5700 for (y
= y1
; y
<= y2
; y
++)
5701 selection_setpoint(x
, y
, pt
, 1);
5703 splev_stack_push(coder
->stack
, pt
);
5707 case SPO_SEL_LINE
: {
5708 struct opvar
*tmp
= NULL
, *tmp2
= NULL
,
5709 *pt
= selection_opvar((char *) 0);
5710 schar x1
, y1
, x2
, y2
;
5713 panic("no ter sel linecoord1");
5714 if (!OV_pop_c(tmp2
))
5715 panic("no ter sel linecoord2");
5716 get_location_coord(&x1
, &y1
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5717 get_location_coord(&x2
, &y2
, ANY_LOC
, coder
->croom
, OV_i(tmp2
));
5718 x1
= (x1
< 0) ? 0 : x1
;
5719 y1
= (y1
< 0) ? 0 : y1
;
5720 x2
= (x2
>= COLNO
) ? COLNO
- 1 : x2
;
5721 y2
= (y2
>= ROWNO
) ? ROWNO
- 1 : y2
;
5722 selection_do_line(x1
, y1
, x2
, y2
, pt
);
5723 splev_stack_push(coder
->stack
, pt
);
5728 case SPO_SEL_RNDLINE
: {
5729 struct opvar
*tmp
= NULL
, *tmp2
= NULL
, *tmp3
,
5730 *pt
= selection_opvar((char *) 0);
5731 schar x1
, y1
, x2
, y2
;
5733 if (!OV_pop_i(tmp3
))
5734 panic("no ter sel randline1");
5736 panic("no ter sel randline2");
5737 if (!OV_pop_c(tmp2
))
5738 panic("no ter sel randline3");
5739 get_location_coord(&x1
, &y1
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5740 get_location_coord(&x2
, &y2
, ANY_LOC
, coder
->croom
, OV_i(tmp2
));
5741 x1
= (x1
< 0) ? 0 : x1
;
5742 y1
= (y1
< 0) ? 0 : y1
;
5743 x2
= (x2
>= COLNO
) ? COLNO
- 1 : x2
;
5744 y2
= (y2
>= ROWNO
) ? ROWNO
- 1 : y2
;
5745 selection_do_randline(x1
, y1
, x2
, y2
, OV_i(tmp3
), 12, pt
);
5746 splev_stack_push(coder
->stack
, pt
);
5752 case SPO_SEL_GROW
: {
5753 struct opvar
*dirs
, *pt
;
5755 if (!OV_pop_i(dirs
))
5756 panic("no dirs for grow");
5757 if (!OV_pop_typ(pt
, SPOVAR_SEL
))
5758 panic("no selection for grow");
5759 selection_do_grow(pt
, OV_i(dirs
));
5760 splev_stack_push(coder
->stack
, pt
);
5764 case SPO_SEL_FLOOD
: {
5769 panic("no ter sel flood coord");
5770 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(tmp
));
5772 struct opvar
*pt
= selection_opvar((char *) 0);
5774 set_selection_floodfillchk(floodfillchk_match_under
);
5775 floodfillchk_match_under_typ
= levl
[x
][y
].typ
;
5776 selection_floodfill(pt
, x
, y
, FALSE
);
5777 splev_stack_push(coder
->stack
, pt
);
5782 case SPO_SEL_RNDCOORD
: {
5786 if (!OV_pop_typ(pt
, SPOVAR_SEL
))
5787 panic("no selection for rndcoord");
5788 if (selection_rndcoord(pt
, &x
, &y
, FALSE
)) {
5792 splev_stack_push(coder
->stack
, opvar_new_coord(x
, y
));
5796 case SPO_SEL_ELLIPSE
: {
5797 struct opvar
*filled
, *xaxis
, *yaxis
, *pt
;
5798 struct opvar
*sel
= selection_opvar((char *) 0);
5801 if (!OV_pop_i(filled
))
5802 panic("no filled for ellipse");
5803 if (!OV_pop_i(yaxis
))
5804 panic("no yaxis for ellipse");
5805 if (!OV_pop_i(xaxis
))
5806 panic("no xaxis for ellipse");
5808 panic("no pt for ellipse");
5809 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(pt
));
5810 selection_do_ellipse(sel
, x
, y
, OV_i(xaxis
), OV_i(yaxis
),
5812 splev_stack_push(coder
->stack
, sel
);
5819 case SPO_SEL_GRADIENT
: {
5820 struct opvar
*gtyp
, *glim
, *mind
, *maxd
, *gcoord
, *coord2
;
5824 if (!OV_pop_i(gtyp
))
5825 panic("no gtyp for grad");
5826 if (!OV_pop_i(glim
))
5827 panic("no glim for grad");
5828 if (!OV_pop_c(coord2
))
5829 panic("no coord2 for grad");
5830 if (!OV_pop_c(gcoord
))
5831 panic("no coord for grad");
5832 if (!OV_pop_i(maxd
))
5833 panic("no maxd for grad");
5834 if (!OV_pop_i(mind
))
5835 panic("no mind for grad");
5836 get_location_coord(&x
, &y
, ANY_LOC
, coder
->croom
, OV_i(gcoord
));
5837 get_location_coord(&x2
, &y2
, ANY_LOC
, coder
->croom
, OV_i(coord2
));
5839 sel
= selection_opvar((char *) 0);
5840 selection_do_gradient(sel
, x
, y
, x2
, y2
, OV_i(gtyp
), OV_i(mind
),
5841 OV_i(maxd
), OV_i(glim
));
5842 splev_stack_push(coder
->stack
, sel
);
5853 panic("sp_level_coder: Unknown opcode %i", coder
->opcode
);
5857 coder
->frame
->n_opcode
++;
5862 remove_boundary_syms();
5864 if (coder
->check_inaccessibles
)
5866 /* FIXME: Ideally, we want this call to only cover areas of the map
5867 * which were not inserted directly by the special level file (see
5868 * the insect legs on Baalzebub's level, for instance). Since that
5869 * is currently not possible, we overload the corrmaze flag for this
5872 if (!level
.flags
.corrmaze
)
5873 wallification(1, 0, COLNO
- 1, ROWNO
- 1);
5877 if (coder
->solidify
)
5880 /* This must be done before sokoban_detect(),
5881 * otherwise branch stairs won't be premapped. */
5884 if (coder
->premapped
)
5888 struct sp_frame
*tmpframe
;
5890 tmpframe
= coder
->frame
->next
;
5891 frame_del(coder
->frame
);
5892 coder
->frame
= tmpframe
;
5893 } while (coder
->frame
);
5909 boolean result
= FALSE
;
5910 struct version_info vers_info
;
5912 fd
= dlb_fopen(name
, RDBMODE
);
5915 Fread((genericptr_t
) &vers_info
, sizeof vers_info
, 1, fd
);
5916 if (!check_version(&vers_info
, name
, TRUE
)) {
5917 (void) dlb_fclose(fd
);
5921 lvl
= (sp_lev
*) alloc(sizeof (sp_lev
));
5922 result
= sp_level_loader(fd
, lvl
);
5923 (void) dlb_fclose(fd
);
5925 result
= sp_level_coder(lvl
);
5934 #pragma warning(pop)