Source:NetHack 3.6.1/src/sp lev.c
(Redirected from Source:Ref/dig corridor)
Jump to navigation
Jump to search
Below is the full text to sp_lev.c from the source code of NetHack 3.6.1. To link to a particular line, write [[Source:NetHack 3.6.1/src/sp_lev.c#line123]], for example.
Contents
- 1 Top of file
- 2 solidify_map
- 3 splev_stack_init
- 4 splev_stack_done
- 5 splev_stack_push
- 6 splev_stack_pop
- 7 splev_stack_reverse
- 8 opvar_new_str
- 9 opvar_new_int
- 10 opvar_new_coord
- 11 opvar_free_x
- 12 opvar_clone
- 13 opvar_var_conversion
- 14 opvar_var_defined
- 15 splev_stack_getdat
- 16 splev_stack_getdat_any
- 17 variable_list_del
- 18 lvlfill_maze_grid
- 19 lvlfill_solid
- 20 set_wall_property
- 21 shuffle_alignments
- 22 count_features
- 23 remove_boundary_syms
- 24 set_door_orientation
- 25 maybe_add_door
- 26 link_doors_rooms
- 27 fill_rooms
- 28 rnddoor
- 29 rndtrap
- 30 get_location
- 31 is_ok_location
- 32 get_unpacked_coord
- 33 get_location_coord
- 34 get_room_loc
- 35 get_free_room_loc
- 36 check_room
- 37 create_room
- 38 create_subroom
- 39 create_door
- 40 create_secret_door
- 41 create_trap
- 42 noncoalignment
- 43 m_bad_boulder_spot
- 44 pm_to_humidity
- 45 create_monster
- 46 create_object
- 47 create_altar
- 48 replace_terrain
- 49 search_door
- 50 dig_corridor
- 51 fix_stair_rooms
- 52 create_corridor
- 53 fill_room
- 54 build_room
- 55 light_region
- 56 wallify_map
- 57 maze1xy
- 58 fill_empty_maze
- 59 sp_level_loader
- 60 sp_level_free
- 61 splev_initlev
- 62 frame_new
- 63 frame_del
- 64 spo_frame_push
- 65 spo_frame_pop
- 66 sp_code_jmpaddr
- 67 spo_call
- 68 spo_return
- 69 spo_end_moninvent
- 70 spo_pop_container
- 71 spo_message
- 72 spo_monster
- 73 spo_object
- 74 spo_level_flags
- 75 spo_initlevel
- 76 spo_engraving
- 77 spo_mineralize
- 78 spo_room
- 79 spo_endroom
- 80 spo_stair
- 81 spo_ladder
- 82 spo_grave
- 83 spo_altar
- 84 spo_trap
- 85 spo_gold
- 86 spo_corridor
- 87 selection_opvar
- 88 selection_getpoint
- 89 selection_setpoint
- 90 selection_not
- 91 selection_logical_oper
- 92 selection_filter_mapchar
- 93 selection_filter_percent
- 94 selection_rndcoord
- 95 selection_do_grow
- 96 set_selection_floodfillchk
- 97 floodfillchk_match_under
- 98 floodfillchk_match_accessible
- 99 selection_floodfill
- 100 selection_do_ellipse
- 101 line_dist_coord
- 102 selection_do_gradient
- 103 selection_do_line
- 104 selection_do_randline
- 105 selection_iterate
- 106 sel_set_ter
- 107 sel_set_feature
- 108 sel_set_door
- 109 spo_door
- 110 spo_feature
- 111 spo_terrain
- 112 spo_replace_terrain
- 113 generate_way_out_method
- 114 ensure_way_out
- 115 spo_levregion
- 116 spo_region
- 117 spo_drawbridge
- 118 spo_mazewalk
- 119 spo_wall_property
- 120 spo_room_door
- 121 sel_set_wallify
- 122 spo_wallify
- 123 spo_map
- 124 spo_jmp
- 125 spo_conditional_jump
- 126 spo_var_init
- 127 spo_shuffle_array
- 128 sp_level_coder
- 129 load_special
Top of file
/* NetHack 3.6 sp_lev.c $NHDT-Date: 1524287226 2018/04/21 05:07:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */
/* Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
/*
* This file contains the various functions that are related to the special
* levels.
*
* It contains also the special level loader.
*/
#include "hack.h"
#include "dlb.h"
#include "sp_lev.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4244)
#endif
typedef void FDECL((*select_iter_func), (int, int, genericptr));
extern void FDECL(mkmap, (lev_init *));
STATIC_DCL void NDECL(solidify_map);
STATIC_DCL void FDECL(splev_stack_init, (struct splevstack *));
STATIC_DCL void FDECL(splev_stack_done, (struct splevstack *));
STATIC_DCL void FDECL(splev_stack_push, (struct splevstack *,
struct opvar *));
STATIC_DCL struct opvar *FDECL(splev_stack_pop, (struct splevstack *));
STATIC_DCL struct splevstack *FDECL(splev_stack_reverse,
(struct splevstack *));
STATIC_DCL struct opvar *FDECL(opvar_new_str, (char *));
STATIC_DCL struct opvar *FDECL(opvar_new_int, (long));
STATIC_DCL struct opvar *FDECL(opvar_new_coord, (int, int));
#if 0
STATIC_DCL struct opvar * FDECL(opvar_new_region, (int,int, int,int));
#endif /*0*/
STATIC_DCL struct opvar *FDECL(opvar_clone, (struct opvar *));
STATIC_DCL struct opvar *FDECL(opvar_var_conversion, (struct sp_coder *,
struct opvar *));
STATIC_DCL struct splev_var *FDECL(opvar_var_defined, (struct sp_coder *,
char *));
STATIC_DCL struct opvar *FDECL(splev_stack_getdat, (struct sp_coder *,
XCHAR_P));
STATIC_DCL struct opvar *FDECL(splev_stack_getdat_any, (struct sp_coder *));
STATIC_DCL void FDECL(variable_list_del, (struct splev_var *));
STATIC_DCL void FDECL(lvlfill_maze_grid, (int, int, int, int, SCHAR_P));
STATIC_DCL void FDECL(lvlfill_solid, (SCHAR_P, SCHAR_P));
STATIC_DCL void FDECL(set_wall_property, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P,
int));
STATIC_DCL void NDECL(shuffle_alignments);
STATIC_DCL void NDECL(count_features);
STATIC_DCL void NDECL(remove_boundary_syms);
STATIC_DCL void FDECL(set_door_orientation, (int, int));
STATIC_DCL void FDECL(maybe_add_door, (int, int, struct mkroom *));
STATIC_DCL void NDECL(link_doors_rooms);
STATIC_DCL void NDECL(fill_rooms);
STATIC_DCL int NDECL(rnddoor);
STATIC_DCL int NDECL(rndtrap);
STATIC_DCL void FDECL(get_location, (schar *, schar *, int, struct mkroom *));
STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
STATIC_DCL unpacked_coord FDECL(get_unpacked_coord, (long, int));
STATIC_DCL void FDECL(get_location_coord, (schar *, schar *, int,
struct mkroom *, long));
STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *,
struct mkroom *, packed_coord));
STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
STATIC_DCL void FDECL(create_trap, (spltrap *, struct mkroom *));
STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
STATIC_DCL boolean FDECL(m_bad_boulder_spot, (int, int));
STATIC_DCL int FDECL(pm_to_humidity, (struct permonst *));
STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
STATIC_DCL void FDECL(replace_terrain, (replaceterrain *, struct mkroom *));
STATIC_DCL boolean FDECL(search_door, (struct mkroom *,
xchar *, xchar *, XCHAR_P, int));
STATIC_DCL void NDECL(fix_stair_rooms);
STATIC_DCL void FDECL(create_corridor, (corridor *));
STATIC_DCL struct mkroom *FDECL(build_room, (room *, struct mkroom *));
STATIC_DCL void FDECL(light_region, (region *));
STATIC_DCL void FDECL(wallify_map, (int, int, int, int));
STATIC_DCL void FDECL(maze1xy, (coord *, int));
STATIC_DCL void NDECL(fill_empty_maze);
STATIC_DCL boolean FDECL(sp_level_loader, (dlb *, sp_lev *));
STATIC_DCL boolean FDECL(sp_level_free, (sp_lev *));
STATIC_DCL void FDECL(splev_initlev, (lev_init *));
STATIC_DCL struct sp_frame *FDECL(frame_new, (long));
STATIC_DCL void FDECL(frame_del, (struct sp_frame *));
STATIC_DCL void FDECL(spo_frame_push, (struct sp_coder *));
STATIC_DCL void FDECL(spo_frame_pop, (struct sp_coder *));
STATIC_DCL long FDECL(sp_code_jmpaddr, (long, long));
STATIC_DCL void FDECL(spo_call, (struct sp_coder *));
STATIC_DCL void FDECL(spo_return, (struct sp_coder *));
STATIC_DCL void FDECL(spo_end_moninvent, (struct sp_coder *));
STATIC_DCL void FDECL(spo_pop_container, (struct sp_coder *));
STATIC_DCL void FDECL(spo_message, (struct sp_coder *));
STATIC_DCL void FDECL(spo_monster, (struct sp_coder *));
STATIC_DCL void FDECL(spo_object, (struct sp_coder *));
STATIC_DCL void FDECL(spo_level_flags, (struct sp_coder *));
STATIC_DCL void FDECL(spo_initlevel, (struct sp_coder *));
STATIC_DCL void FDECL(spo_engraving, (struct sp_coder *));
STATIC_DCL void FDECL(spo_mineralize, (struct sp_coder *));
STATIC_DCL void FDECL(spo_room, (struct sp_coder *));
STATIC_DCL void FDECL(spo_endroom, (struct sp_coder *));
STATIC_DCL void FDECL(spo_stair, (struct sp_coder *));
STATIC_DCL void FDECL(spo_ladder, (struct sp_coder *));
STATIC_DCL void FDECL(spo_grave, (struct sp_coder *));
STATIC_DCL void FDECL(spo_altar, (struct sp_coder *));
STATIC_DCL void FDECL(spo_trap, (struct sp_coder *));
STATIC_DCL void FDECL(spo_gold, (struct sp_coder *));
STATIC_DCL void FDECL(spo_corridor, (struct sp_coder *));
STATIC_DCL void FDECL(selection_setpoint, (int, int, struct opvar *, XCHAR_P));
STATIC_DCL struct opvar *FDECL(selection_not, (struct opvar *));
STATIC_DCL struct opvar *FDECL(selection_logical_oper, (struct opvar *,
struct opvar *, CHAR_P));
STATIC_DCL struct opvar *FDECL(selection_filter_mapchar, (struct opvar *,
struct opvar *));
STATIC_DCL void FDECL(selection_filter_percent, (struct opvar *, int));
STATIC_DCL int FDECL(selection_rndcoord, (struct opvar *, schar *, schar *,
BOOLEAN_P));
STATIC_DCL void FDECL(selection_do_grow, (struct opvar *, int));
STATIC_DCL int FDECL(floodfillchk_match_under, (int, int));
STATIC_DCL int FDECL(floodfillchk_match_accessible, (int, int));
STATIC_DCL void FDECL(selection_do_ellipse, (struct opvar *, int, int,
int, int, int));
STATIC_DCL long FDECL(line_dist_coord, (long, long, long, long, long, long));
STATIC_DCL void FDECL(selection_do_gradient, (struct opvar *, long, long, long,
long, long, long, long, long));
STATIC_DCL void FDECL(selection_do_line, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P,
struct opvar *));
STATIC_DCL void FDECL(selection_do_randline, (SCHAR_P, SCHAR_P, SCHAR_P,
SCHAR_P, SCHAR_P, SCHAR_P,
struct opvar *));
STATIC_DCL void FDECL(selection_iterate, (struct opvar *, select_iter_func,
genericptr_t));
STATIC_DCL void FDECL(sel_set_ter, (int, int, genericptr_t));
STATIC_DCL void FDECL(sel_set_feature, (int, int, genericptr_t));
STATIC_DCL void FDECL(sel_set_door, (int, int, genericptr_t));
STATIC_DCL void FDECL(spo_door, (struct sp_coder *));
STATIC_DCL void FDECL(spo_feature, (struct sp_coder *));
STATIC_DCL void FDECL(spo_terrain, (struct sp_coder *));
STATIC_DCL void FDECL(spo_replace_terrain, (struct sp_coder *));
STATIC_DCL boolean FDECL(generate_way_out_method, (int, int, struct opvar *));
STATIC_DCL void NDECL(ensure_way_out);
STATIC_DCL void FDECL(spo_levregion, (struct sp_coder *));
STATIC_DCL void FDECL(spo_region, (struct sp_coder *));
STATIC_DCL void FDECL(spo_drawbridge, (struct sp_coder *));
STATIC_DCL void FDECL(spo_mazewalk, (struct sp_coder *));
STATIC_DCL void FDECL(spo_wall_property, (struct sp_coder *));
STATIC_DCL void FDECL(spo_room_door, (struct sp_coder *));
STATIC_DCL void FDECL(sel_set_wallify, (int, int, genericptr_t));
STATIC_DCL void FDECL(spo_wallify, (struct sp_coder *));
STATIC_DCL void FDECL(spo_map, (struct sp_coder *));
STATIC_DCL void FDECL(spo_jmp, (struct sp_coder *, sp_lev *));
STATIC_DCL void FDECL(spo_conditional_jump, (struct sp_coder *, sp_lev *));
STATIC_DCL void FDECL(spo_var_init, (struct sp_coder *));
#if 0
STATIC_DCL long FDECL(opvar_array_length, (struct sp_coder *));
#endif /*0*/
STATIC_DCL void FDECL(spo_shuffle_array, (struct sp_coder *));
STATIC_DCL boolean FDECL(sp_level_coder, (sp_lev *));
#define LEFT 1
#define H_LEFT 2
#define CENTER 3
#define H_RIGHT 4
#define RIGHT 5
#define TOP 1
#define BOTTOM 5
#define sq(x) ((x) * (x))
#define XLIM 4
#define YLIM 3
#define Fread (void) dlb_fread
#define Fgetc (schar) dlb_fgetc
#define New(type) (type *) alloc(sizeof(type))
#define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned) size)
#define Free(ptr) if (ptr) free((genericptr_t) (ptr))
extern struct engr *head_engr;
extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
/* positions touched by level elements explicitly defined in the des-file */
static char SpLev_Map[COLNO][ROWNO];
static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
static NEARDATA xchar xstart, ystart;
static NEARDATA char xsize, ysize;
char *lev_message = 0;
lev_region *lregions = 0;
int num_lregions = 0;
static boolean splev_init_present = FALSE;
static boolean icedpools = FALSE;
static int mines_prize_count = 0, soko_prize_count = 0; /* achievements */
static struct obj *container_obj[MAX_CONTAINMENT];
static int container_idx = 0;
static struct monst *invent_carrying_monster = NULL;
#define SPLEV_STACK_RESERVE 128
solidify_map
void
solidify_map()
{
xchar x, y;
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (IS_STWALL(levl[x][y].typ) && !SpLev_Map[x][y])
levl[x][y].wall_info |= (W_NONDIGGABLE | W_NONPASSWALL);
}
splev_stack_init
void
splev_stack_init(st)
struct splevstack *st;
{
if (st) {
st->depth = 0;
st->depth_alloc = SPLEV_STACK_RESERVE;
st->stackdata =
(struct opvar **) alloc(st->depth_alloc * sizeof(struct opvar *));
}
}
splev_stack_done
void
splev_stack_done(st)
struct splevstack *st;
{
if (st) {
int i;
if (st->stackdata && st->depth) {
for (i = 0; i < st->depth; i++) {
switch (st->stackdata[i]->spovartyp) {
default:
case SPOVAR_NULL:
case SPOVAR_COORD:
case SPOVAR_REGION:
case SPOVAR_MAPCHAR:
case SPOVAR_MONST:
case SPOVAR_OBJ:
case SPOVAR_INT:
break;
case SPOVAR_VARIABLE:
case SPOVAR_STRING:
case SPOVAR_SEL:
Free(st->stackdata[i]->vardata.str);
st->stackdata[i]->vardata.str = NULL;
break;
}
Free(st->stackdata[i]);
st->stackdata[i] = NULL;
}
}
Free(st->stackdata);
st->stackdata = NULL;
st->depth = st->depth_alloc = 0;
Free(st);
}
}
splev_stack_push
void
splev_stack_push(st, v)
struct splevstack *st;
struct opvar *v;
{
if (!st || !v)
return;
if (!st->stackdata)
panic("splev_stack_push: no stackdata allocated?");
if (st->depth >= st->depth_alloc) {
struct opvar **tmp = (struct opvar **) alloc(
(st->depth_alloc + SPLEV_STACK_RESERVE) * sizeof(struct opvar *));
(void) memcpy(tmp, st->stackdata,
st->depth_alloc * sizeof(struct opvar *));
Free(st->stackdata);
st->stackdata = tmp;
st->depth_alloc += SPLEV_STACK_RESERVE;
}
st->stackdata[st->depth] = v;
st->depth++;
}
splev_stack_pop
struct opvar *
splev_stack_pop(st)
struct splevstack *st;
{
struct opvar *ret = NULL;
if (!st)
return ret;
if (!st->stackdata)
panic("splev_stack_pop: no stackdata allocated?");
if (st->depth) {
st->depth--;
ret = st->stackdata[st->depth];
st->stackdata[st->depth] = NULL;
return ret;
} else
impossible("splev_stack_pop: empty stack?");
return ret;
}
splev_stack_reverse
struct splevstack *
splev_stack_reverse(st)
struct splevstack *st;
{
long i;
struct opvar *tmp;
if (!st)
return NULL;
if (!st->stackdata)
panic("splev_stack_reverse: no stackdata allocated?");
for (i = 0; i < (st->depth / 2); i++) {
tmp = st->stackdata[i];
st->stackdata[i] = st->stackdata[st->depth - i - 1];
st->stackdata[st->depth - i - 1] = tmp;
}
return st;
}
#define OV_typ(o) (o->spovartyp)
#define OV_i(o) (o->vardata.l)
#define OV_s(o) (o->vardata.str)
#define OV_pop_i(x) (x = splev_stack_getdat(coder, SPOVAR_INT))
#define OV_pop_c(x) (x = splev_stack_getdat(coder, SPOVAR_COORD))
#define OV_pop_r(x) (x = splev_stack_getdat(coder, SPOVAR_REGION))
#define OV_pop_s(x) (x = splev_stack_getdat(coder, SPOVAR_STRING))
#define OV_pop(x) (x = splev_stack_getdat_any(coder))
#define OV_pop_typ(x, typ) (x = splev_stack_getdat(coder, typ))
opvar_new_str
struct opvar *
opvar_new_str(s)
char *s;
{
struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar));
tmpov->spovartyp = SPOVAR_STRING;
if (s) {
int len = strlen(s);
tmpov->vardata.str = (char *) alloc(len + 1);
(void) memcpy((genericptr_t) tmpov->vardata.str, (genericptr_t) s,
len);
tmpov->vardata.str[len] = '\0';
} else
tmpov->vardata.str = NULL;
return tmpov;
}
opvar_new_int
struct opvar *
opvar_new_int(i)
long i;
{
struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar));
tmpov->spovartyp = SPOVAR_INT;
tmpov->vardata.l = i;
return tmpov;
}
opvar_new_coord
struct opvar *
opvar_new_coord(x, y)
int x, y;
{
struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar));
tmpov->spovartyp = SPOVAR_COORD;
tmpov->vardata.l = SP_COORD_PACK(x, y);
return tmpov;
}
#if 0
struct opvar *
opvar_new_region(x1,y1,x2,y2)
int x1,y1,x2,y2;
{
struct opvar *tmpov = (struct opvar *)alloc(sizeof (struct opvar));
tmpov->spovartyp = SPOVAR_REGION;
tmpov->vardata.l = SP_REGION_PACK(x1,y1,x2,y2);
return tmpov;
}
#endif /*0*/
opvar_free_x
void
opvar_free_x(ov)
struct opvar *ov;
{
if (!ov)
return;
switch (ov->spovartyp) {
case SPOVAR_COORD:
case SPOVAR_REGION:
case SPOVAR_MAPCHAR:
case SPOVAR_MONST:
case SPOVAR_OBJ:
case SPOVAR_INT:
break;
case SPOVAR_VARIABLE:
case SPOVAR_STRING:
case SPOVAR_SEL:
Free(ov->vardata.str);
break;
default:
impossible("Unknown opvar value type (%i)!", ov->spovartyp);
}
Free(ov);
}
/*
* Name of current function for use in messages:
* __func__ -- C99 standard;
* __FUNCTION__ -- gcc extension, starting before C99 and continuing after;
* picked up by other compilers (or vice versa?);
* __FUNC__ -- supported by Borland;
* nhFunc -- slightly intrusive but fully portable nethack construct
* for any version of any compiler.
*/
#define opvar_free(ov) \
do { \
if (ov) { \
opvar_free_x(ov); \
ov = NULL; \
} else \
impossible("opvar_free(), %s", nhFunc); \
} while (0)
opvar_clone
struct opvar *
opvar_clone(ov)
struct opvar *ov;
{
struct opvar *tmpov;
if (!ov)
panic("no opvar to clone");
tmpov = (struct opvar *) alloc(sizeof(struct opvar));
tmpov->spovartyp = ov->spovartyp;
switch (ov->spovartyp) {
case SPOVAR_COORD:
case SPOVAR_REGION:
case SPOVAR_MAPCHAR:
case SPOVAR_MONST:
case SPOVAR_OBJ:
case SPOVAR_INT:
tmpov->vardata.l = ov->vardata.l;
break;
case SPOVAR_VARIABLE:
case SPOVAR_STRING:
case SPOVAR_SEL:
tmpov->vardata.str = dupstr(ov->vardata.str);
break;
default:
impossible("Unknown push value type (%i)!", ov->spovartyp);
}
return tmpov;
}
opvar_var_conversion
struct opvar *
opvar_var_conversion(coder, ov)
struct sp_coder *coder;
struct opvar *ov;
{
static const char nhFunc[] = "opvar_var_conversion";
struct splev_var *tmp;
struct opvar *tmpov;
struct opvar *array_idx = NULL;
if (!coder || !ov)
return NULL;
if (ov->spovartyp != SPOVAR_VARIABLE)
return ov;
tmp = coder->frame->variables;
while (tmp) {
if (!strcmp(tmp->name, OV_s(ov))) {
if ((tmp->svtyp & SPOVAR_ARRAY)) {
array_idx = opvar_var_conversion(coder,
splev_stack_pop(coder->stack));
if (!array_idx || OV_typ(array_idx) != SPOVAR_INT)
panic("array idx not an int");
if (tmp->array_len < 1)
panic("array len < 1");
OV_i(array_idx) = (OV_i(array_idx) % tmp->array_len);
tmpov = opvar_clone(tmp->data.arrayvalues[OV_i(array_idx)]);
opvar_free(array_idx);
return tmpov;
} else {
tmpov = opvar_clone(tmp->data.value);
return tmpov;
}
}
tmp = tmp->next;
}
return NULL;
}
opvar_var_defined
struct splev_var *
opvar_var_defined(coder, name)
struct sp_coder *coder;
char *name;
{
struct splev_var *tmp;
if (!coder)
return NULL;
tmp = coder->frame->variables;
while (tmp) {
if (!strcmp(tmp->name, name))
return tmp;
tmp = tmp->next;
}
return NULL;
}
splev_stack_getdat
struct opvar *
splev_stack_getdat(coder, typ)
struct sp_coder *coder;
xchar typ;
{
static const char nhFunc[] = "splev_stack_getdat";
if (coder && coder->stack) {
struct opvar *tmp = splev_stack_pop(coder->stack);
struct opvar *ret = NULL;
if (!tmp)
panic("no value type %i in stack.", typ);
if (tmp->spovartyp == SPOVAR_VARIABLE) {
ret = opvar_var_conversion(coder, tmp);
opvar_free(tmp);
tmp = ret;
}
if (tmp->spovartyp == typ)
return tmp;
else opvar_free(tmp);
}
return NULL;
}
splev_stack_getdat_any
struct opvar *
splev_stack_getdat_any(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "splev_stack_getdat_any";
if (coder && coder->stack) {
struct opvar *tmp = splev_stack_pop(coder->stack);
if (tmp && tmp->spovartyp == SPOVAR_VARIABLE) {
struct opvar *ret = opvar_var_conversion(coder, tmp);
opvar_free(tmp);
return ret;
}
return tmp;
}
return NULL;
}
variable_list_del
void
variable_list_del(varlist)
struct splev_var *varlist;
{
static const char nhFunc[] = "variable_list_del";
struct splev_var *tmp = varlist;
if (!tmp)
return;
while (tmp) {
Free(tmp->name);
if ((tmp->svtyp & SPOVAR_ARRAY)) {
long idx = tmp->array_len;
while (idx-- > 0) {
opvar_free(tmp->data.arrayvalues[idx]);
};
Free(tmp->data.arrayvalues);
} else {
opvar_free(tmp->data.value);
}
tmp = varlist->next;
Free(varlist);
varlist = tmp;
}
}
lvlfill_maze_grid
void
lvlfill_maze_grid(x1, y1, x2, y2, filling)
int x1, y1, x2, y2;
schar filling;
{
int x, y;
for (x = x1; x <= x2; x++)
for (y = y1; y <= y2; y++) {
if (level.flags.corrmaze)
levl[x][y].typ = STONE;
else
levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE
: filling;
}
}
lvlfill_solid
void
lvlfill_solid(filling, lit)
schar filling;
schar lit;
{
int x, y;
for (x = 2; x <= x_maze_max; x++)
for (y = 0; y <= y_maze_max; y++) {
SET_TYPLIT(x, y, filling, lit);
}
}
set_wall_property
/*
* Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
*/
STATIC_OVL void
set_wall_property(x1, y1, x2, y2, prop)
xchar x1, y1, x2, y2;
int prop;
{
register xchar x, y;
for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++)
for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++)
if (IS_STWALL(levl[x][y].typ) || IS_TREE(levl[x][y].typ))
levl[x][y].wall_info |= prop;
}
shuffle_alignments
STATIC_OVL void
shuffle_alignments()
{
int i;
aligntyp atmp;
/* shuffle 3 alignments */
i = rn2(3);
atmp = ralign[2];
ralign[2] = ralign[i];
ralign[i] = atmp;
if (rn2(2)) {
atmp = ralign[1];
ralign[1] = ralign[0];
ralign[0] = atmp;
}
}
count_features
/*
* Count the different features (sinks, fountains) in the level.
*/
STATIC_OVL void
count_features()
{
xchar x, y;
level.flags.nfountains = level.flags.nsinks = 0;
for (y = 0; y < ROWNO; y++)
for (x = 0; x < COLNO; x++) {
int typ = levl[x][y].typ;
if (typ == FOUNTAIN)
level.flags.nfountains++;
else if (typ == SINK)
level.flags.nsinks++;
}
}
remove_boundary_syms
void
remove_boundary_syms()
{
/*
* If any CROSSWALLs are found, must change to ROOM after REGION's
* are laid out. CROSSWALLS are used to specify "invisible"
* boundaries where DOOR syms look bad or aren't desirable.
*/
xchar x, y;
boolean has_bounds = FALSE;
for (x = 0; x < COLNO - 1; x++)
for (y = 0; y < ROWNO - 1; y++)
if (levl[x][y].typ == CROSSWALL) {
has_bounds = TRUE;
break;
}
if (has_bounds) {
for (x = 0; x < x_maze_max; x++)
for (y = 0; y < y_maze_max; y++)
if ((levl[x][y].typ == CROSSWALL) && SpLev_Map[x][y])
levl[x][y].typ = ROOM;
}
}
set_door_orientation
/* used by sel_set_door() and link_doors_rooms() */
STATIC_OVL void
set_door_orientation(x, y)
int x, y;
{
boolean wleft, wright, wup, wdown;
/* If there's a wall or door on either the left side or right
* side (or both) of this secret door, make it be horizontal.
*
* It is feasible to put SDOOR in a corner, tee, or crosswall
* position, although once the door is found and opened it won't
* make a lot sense (diagonal access required). Still, we try to
* handle that as best as possible. For top or bottom tee, using
* horizontal is the best we can do. For corner or crosswall,
* either horizontal or vertical are just as good as each other;
* we produce horizontal for corners and vertical for crosswalls.
* For left or right tee, using vertical is best.
*
* A secret door with no adjacent walls is also feasible and makes
* even less sense. It will be displayed as a vertical wall while
* hidden and become a vertical door when found. Before resorting
* to that, we check for solid rock which hasn't been wallified
* yet (cf lower leftside of leader's room in Cav quest).
*/
wleft = (isok(x - 1, y) && (IS_WALL(levl[x - 1][y].typ)
|| IS_DOOR(levl[x - 1][y].typ)
|| levl[x - 1][y].typ == SDOOR));
wright = (isok(x + 1, y) && (IS_WALL(levl[x + 1][y].typ)
|| IS_DOOR(levl[x + 1][y].typ)
|| levl[x + 1][y].typ == SDOOR));
wup = (isok(x, y - 1) && (IS_WALL(levl[x][y - 1].typ)
|| IS_DOOR(levl[x][y - 1].typ)
|| levl[x][y - 1].typ == SDOOR));
wdown = (isok(x, y + 1) && (IS_WALL(levl[x][y + 1].typ)
|| IS_DOOR(levl[x][y + 1].typ)
|| levl[x][y + 1].typ == SDOOR));
if (!wleft && !wright && !wup && !wdown) {
/* out of bounds is treated as implicit wall; should be academic
because we don't expect to have doors so near the level's edge */
wleft = (!isok(x - 1, y) || IS_DOORJOIN(levl[x - 1][y].typ));
wright = (!isok(x + 1, y) || IS_DOORJOIN(levl[x + 1][y].typ));
wup = (!isok(x, y - 1) || IS_DOORJOIN(levl[x][y - 1].typ));
wdown = (!isok(x, y + 1) || IS_DOORJOIN(levl[x][y + 1].typ));
}
levl[x][y].horizontal = ((wleft || wright) && !(wup && wdown)) ? 1 : 0;
}
maybe_add_door
STATIC_OVL void
maybe_add_door(x, y, droom)
int x, y;
struct mkroom *droom;
{
if (droom->hx >= 0 && doorindex < DOORMAX && inside_room(droom, x, y))
add_door(x, y, droom);
}
link_doors_rooms
STATIC_OVL void
link_doors_rooms()
{
int x, y;
int tmpi, m;
for (y = 0; y < ROWNO; y++)
for (x = 0; x < COLNO; x++)
if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) {
/* in case this door was a '+' or 'S' from the
MAP...ENDMAP section without an explicit DOOR
directive, set/clear levl[][].horizontal for it */
set_door_orientation(x, y);
for (tmpi = 0; tmpi < nroom; tmpi++) {
maybe_add_door(x, y, &rooms[tmpi]);
for (m = 0; m < rooms[tmpi].nsubrooms; m++) {
maybe_add_door(x, y, rooms[tmpi].sbrooms[m]);
}
}
}
}
fill_rooms
void
fill_rooms()
{
int tmpi;
for (tmpi = 0; tmpi < nroom; tmpi++) {
int m;
if (rooms[tmpi].needfill)
fill_room(&rooms[tmpi], (rooms[tmpi].needfill == 2));
for (m = 0; m < rooms[tmpi].nsubrooms; m++)
if (rooms[tmpi].sbrooms[m]->needfill)
fill_room(rooms[tmpi].sbrooms[m], FALSE);
}
}
rnddoor
/*
* Choose randomly the state (nodoor, open, closed or locked) for a door
*/
STATIC_OVL int
rnddoor()
{
int i = 1 << rn2(5);
i >>= 1;
return i;
}
rndtrap
/*
* Select a random trap
*/
STATIC_OVL int
rndtrap()
{
int rtrap;
do {
rtrap = rnd(TRAPNUM - 1);
switch (rtrap) {
case HOLE: /* no random holes on special levels */
case VIBRATING_SQUARE:
case MAGIC_PORTAL:
rtrap = NO_TRAP;
break;
case TRAPDOOR:
if (!Can_dig_down(&u.uz))
rtrap = NO_TRAP;
break;
case LEVEL_TELEP:
case TELEP_TRAP:
if (level.flags.noteleport)
rtrap = NO_TRAP;
break;
case ROLLING_BOULDER_TRAP:
case ROCKTRAP:
if (In_endgame(&u.uz))
rtrap = NO_TRAP;
break;
}
} while (rtrap == NO_TRAP);
return rtrap;
}
get_location
/*
* Coordinates in special level files are handled specially:
*
* if x or y is < 0, we generate a random coordinate.
* The "humidity" flag is used to insure that engravings aren't
* created underwater, or eels on dry land.
*/
STATIC_OVL void
get_location(x, y, humidity, croom)
schar *x, *y;
int humidity;
struct mkroom *croom;
{
int cpt = 0;
int mx, my, sx, sy;
if (croom) {
mx = croom->lx;
my = croom->ly;
sx = croom->hx - mx + 1;
sy = croom->hy - my + 1;
} else {
mx = xstart;
my = ystart;
sx = xsize;
sy = ysize;
}
if (*x >= 0) { /* normal locations */
*x += mx;
*y += my;
} else { /* random location */
do {
if (croom) { /* handle irregular areas */
coord tmpc;
somexy(croom, &tmpc);
*x = tmpc.x;
*y = tmpc.y;
} else {
*x = mx + rn2((int) sx);
*y = my + rn2((int) sy);
}
if (is_ok_location(*x, *y, humidity))
break;
} while (++cpt < 100);
if (cpt >= 100) {
register int xx, yy;
/* last try */
for (xx = 0; xx < sx; xx++)
for (yy = 0; yy < sy; yy++) {
*x = mx + xx;
*y = my + yy;
if (is_ok_location(*x, *y, humidity))
goto found_it;
}
if (!(humidity & NO_LOC_WARN)) {
impossible("get_location: can't find a place!");
} else {
*x = *y = -1;
}
}
}
found_it:
;
if (!(humidity & ANY_LOC) && !isok(*x, *y)) {
if (!(humidity & NO_LOC_WARN)) {
/*warning("get_location: (%d,%d) out of bounds", *x, *y);*/
*x = x_maze_max;
*y = y_maze_max;
} else {
*x = *y = -1;
}
}
}
is_ok_location
STATIC_OVL boolean
is_ok_location(x, y, humidity)
register schar x, y;
register int humidity;
{
register int typ;
if (Is_waterlevel(&u.uz))
return TRUE; /* accept any spot */
/* TODO: Should perhaps check if wall is diggable/passwall? */
if (humidity & ANY_LOC)
return TRUE;
if ((humidity & SOLID) && IS_ROCK(levl[x][y].typ))
return TRUE;
if (humidity & DRY) {
typ = levl[x][y].typ;
if (typ == ROOM || typ == AIR || typ == CLOUD || typ == ICE
|| typ == CORR)
return TRUE;
}
if ((humidity & SPACELOC) && SPACE_POS(levl[x][y].typ))
return TRUE;
if ((humidity & WET) && is_pool(x, y))
return TRUE;
if ((humidity & HOT) && is_lava(x, y))
return TRUE;
return FALSE;
}
get_unpacked_coord
unpacked_coord
get_unpacked_coord(loc, defhumidity)
long loc;
int defhumidity;
{
static unpacked_coord c;
if (loc & SP_COORD_IS_RANDOM) {
c.x = c.y = -1;
c.is_random = 1;
c.getloc_flags = (loc & ~SP_COORD_IS_RANDOM);
if (!c.getloc_flags)
c.getloc_flags = defhumidity;
} else {
c.is_random = 0;
c.getloc_flags = defhumidity;
c.x = SP_COORD_X(loc);
c.y = SP_COORD_Y(loc);
}
return c;
}
get_location_coord
STATIC_OVL void
get_location_coord(x, y, humidity, croom, crd)
schar *x, *y;
int humidity;
struct mkroom *croom;
long crd;
{
unpacked_coord c;
c = get_unpacked_coord(crd, humidity);
*x = c.x;
*y = c.y;
get_location(x, y, c.getloc_flags | (c.is_random ? NO_LOC_WARN : 0),
croom);
if (*x == -1 && *y == -1 && c.is_random)
get_location(x, y, humidity, croom);
}
get_room_loc
/*
* Get a relative position inside a room.
* negative values for x or y means RANDOM!
*/
STATIC_OVL void
get_room_loc(x, y, croom)
schar *x, *y;
struct mkroom *croom;
{
coord c;
if (*x < 0 && *y < 0) {
if (somexy(croom, &c)) {
*x = c.x;
*y = c.y;
} else
panic("get_room_loc : can't find a place!");
} else {
if (*x < 0)
*x = rn2(croom->hx - croom->lx + 1);
if (*y < 0)
*y = rn2(croom->hy - croom->ly + 1);
*x += croom->lx;
*y += croom->ly;
}
}
get_free_room_loc
/*
* Get a relative position inside a room.
* negative values for x or y means RANDOM!
*/
STATIC_OVL void
get_free_room_loc(x, y, croom, pos)
schar *x, *y;
struct mkroom *croom;
packed_coord pos;
{
schar try_x, try_y;
register int trycnt = 0;
get_location_coord(&try_x, &try_y, DRY, croom, pos);
if (levl[try_x][try_y].typ != ROOM) {
do {
try_x = *x, try_y = *y;
get_room_loc(&try_x, &try_y, croom);
} while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100);
if (trycnt > 100)
panic("get_free_room_loc: can't find a place!");
}
*x = try_x, *y = try_y;
}
check_room
boolean
check_room(lowx, ddx, lowy, ddy, vault)
xchar *lowx, *ddx, *lowy, *ddy;
boolean vault;
{
register int x, y, hix = *lowx + *ddx, hiy = *lowy + *ddy;
register struct rm *lev;
int xlim, ylim, ymax;
xlim = XLIM + (vault ? 1 : 0);
ylim = YLIM + (vault ? 1 : 0);
if (*lowx < 3)
*lowx = 3;
if (*lowy < 2)
*lowy = 2;
if (hix > COLNO - 3)
hix = COLNO - 3;
if (hiy > ROWNO - 3)
hiy = ROWNO - 3;
chk:
if (hix <= *lowx || hiy <= *lowy)
return FALSE;
/* check area around room (and make room smaller if necessary) */
for (x = *lowx - xlim; x <= hix + xlim; x++) {
if (x <= 0 || x >= COLNO)
continue;
y = *lowy - ylim;
ymax = hiy + ylim;
if (y < 0)
y = 0;
if (ymax >= ROWNO)
ymax = (ROWNO - 1);
lev = &levl[x][y];
for (; y <= ymax; y++) {
if (lev++->typ) {
if (!vault) {
debugpline2("strange area [%d,%d] in check_room.", x, y);
}
if (!rn2(3))
return FALSE;
if (x < *lowx)
*lowx = x + xlim + 1;
else
hix = x - xlim - 1;
if (y < *lowy)
*lowy = y + ylim + 1;
else
hiy = y - ylim - 1;
goto chk;
}
}
}
*ddx = hix - *lowx;
*ddy = hiy - *lowy;
return TRUE;
}
create_room
/*
* Create a new room.
* This is still very incomplete...
*/
boolean
create_room(x, y, w, h, xal, yal, rtype, rlit)
xchar x, y;
xchar w, h;
xchar xal, yal;
xchar rtype, rlit;
{
xchar xabs, yabs;
int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp;
NhRect *r1 = 0, r2;
int trycnt = 0;
boolean vault = FALSE;
int xlim = XLIM, ylim = YLIM;
if (rtype == -1) /* Is the type random ? */
rtype = OROOM;
if (rtype == VAULT) {
vault = TRUE;
xlim++;
ylim++;
}
/* on low levels the room is lit (usually) */
/* some other rooms may require lighting */
/* is light state random ? */
if (rlit == -1)
rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
/*
* Here we will try to create a room. If some parameters are
* random we are willing to make several try before we give
* it up.
*/
do {
xchar xborder, yborder;
wtmp = w;
htmp = h;
xtmp = x;
ytmp = y;
xaltmp = xal;
yaltmp = yal;
/* First case : a totally random room */
if ((xtmp < 0 && ytmp < 0 && wtmp < 0 && xaltmp < 0 && yaltmp < 0)
|| vault) {
xchar hx, hy, lx, ly, dx, dy;
r1 = rnd_rect(); /* Get a random rectangle */
if (!r1) { /* No more free rectangles ! */
debugpline0("No more rects...");
return FALSE;
}
hx = r1->hx;
hy = r1->hy;
lx = r1->lx;
ly = r1->ly;
if (vault)
dx = dy = 1;
else {
dx = 2 + rn2((hx - lx > 28) ? 12 : 8);
dy = 2 + rn2(4);
if (dx * dy > 50)
dy = 50 / dx;
}
xborder = (lx > 0 && hx < COLNO - 1) ? 2 * xlim : xlim + 1;
yborder = (ly > 0 && hy < ROWNO - 1) ? 2 * ylim : ylim + 1;
if (hx - lx < dx + 3 + xborder || hy - ly < dy + 3 + yborder) {
r1 = 0;
continue;
}
xabs = lx + (lx > 0 ? xlim : 3)
+ rn2(hx - (lx > 0 ? lx : 3) - dx - xborder + 1);
yabs = ly + (ly > 0 ? ylim : 2)
+ rn2(hy - (ly > 0 ? ly : 2) - dy - yborder + 1);
if (ly == 0 && hy >= (ROWNO - 1) && (!nroom || !rn2(nroom))
&& (yabs + dy > ROWNO / 2)) {
yabs = rn1(3, 2);
if (nroom < 4 && dy > 1)
dy--;
}
if (!check_room(&xabs, &dx, &yabs, &dy, vault)) {
r1 = 0;
continue;
}
wtmp = dx + 1;
htmp = dy + 1;
r2.lx = xabs - 1;
r2.ly = yabs - 1;
r2.hx = xabs + wtmp;
r2.hy = yabs + htmp;
} else { /* Only some parameters are random */
int rndpos = 0;
if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */
xtmp = rnd(5);
ytmp = rnd(5);
rndpos = 1;
}
if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */
wtmp = rn1(15, 3);
htmp = rn1(8, 2);
}
if (xaltmp == -1) /* Horizontal alignment is RANDOM */
xaltmp = rnd(3);
if (yaltmp == -1) /* Vertical alignment is RANDOM */
yaltmp = rnd(3);
/* Try to generate real (absolute) coordinates here! */
xabs = (((xtmp - 1) * COLNO) / 5) + 1;
yabs = (((ytmp - 1) * ROWNO) / 5) + 1;
switch (xaltmp) {
case LEFT:
break;
case RIGHT:
xabs += (COLNO / 5) - wtmp;
break;
case CENTER:
xabs += ((COLNO / 5) - wtmp) / 2;
break;
}
switch (yaltmp) {
case TOP:
break;
case BOTTOM:
yabs += (ROWNO / 5) - htmp;
break;
case CENTER:
yabs += ((ROWNO / 5) - htmp) / 2;
break;
}
if (xabs + wtmp - 1 > COLNO - 2)
xabs = COLNO - wtmp - 3;
if (xabs < 2)
xabs = 2;
if (yabs + htmp - 1 > ROWNO - 2)
yabs = ROWNO - htmp - 3;
if (yabs < 2)
yabs = 2;
/* Try to find a rectangle that fit our room ! */
r2.lx = xabs - 1;
r2.ly = yabs - 1;
r2.hx = xabs + wtmp + rndpos;
r2.hy = yabs + htmp + rndpos;
r1 = get_rect(&r2);
}
} while (++trycnt <= 100 && !r1);
if (!r1) { /* creation of room failed ? */
return FALSE;
}
split_rects(r1, &r2);
if (!vault) {
smeq[nroom] = nroom;
add_room(xabs, yabs, xabs + wtmp - 1, yabs + htmp - 1, rlit, rtype,
FALSE);
} else {
rooms[nroom].lx = xabs;
rooms[nroom].ly = yabs;
}
return TRUE;
}
create_subroom
/*
* Create a subroom in room proom at pos x,y with width w & height h.
* x & y are relative to the parent room.
*/
STATIC_OVL boolean
create_subroom(proom, x, y, w, h, rtype, rlit)
struct mkroom *proom;
xchar x, y;
xchar w, h;
xchar rtype, rlit;
{
xchar width, height;
width = proom->hx - proom->lx + 1;
height = proom->hy - proom->ly + 1;
/* There is a minimum size for the parent room */
if (width < 4 || height < 4)
return FALSE;
/* Check for random position, size, etc... */
if (w == -1)
w = rnd(width - 3);
if (h == -1)
h = rnd(height - 3);
if (x == -1)
x = rnd(width - w - 1) - 1;
if (y == -1)
y = rnd(height - h - 1) - 1;
if (x == 1)
x = 0;
if (y == 1)
y = 0;
if ((x + w + 1) == width)
x++;
if ((y + h + 1) == height)
y++;
if (rtype == -1)
rtype = OROOM;
if (rlit == -1)
rlit = (rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
add_subroom(proom, proom->lx + x, proom->ly + y, proom->lx + x + w - 1,
proom->ly + y + h - 1, rlit, rtype, FALSE);
return TRUE;
}
create_door
/*
* Create a new door in a room.
* It's placed on a wall (north, south, east or west).
*/
STATIC_OVL void
create_door(dd, broom)
room_door *dd;
struct mkroom *broom;
{
int x = 0, y = 0;
int trycnt = 0, wtry = 0;
if (dd->secret == -1)
dd->secret = rn2(2);
if (dd->mask == -1) {
/* is it a locked door, closed, or a doorway? */
if (!dd->secret) {
if (!rn2(3)) {
if (!rn2(5))
dd->mask = D_ISOPEN;
else if (!rn2(6))
dd->mask = D_LOCKED;
else
dd->mask = D_CLOSED;
if (dd->mask != D_ISOPEN && !rn2(25))
dd->mask |= D_TRAPPED;
} else
dd->mask = D_NODOOR;
} else {
if (!rn2(5))
dd->mask = D_LOCKED;
else
dd->mask = D_CLOSED;
if (!rn2(20))
dd->mask |= D_TRAPPED;
}
}
do {
register int dwall, dpos;
dwall = dd->wall;
if (dwall == -1) /* The wall is RANDOM */
dwall = 1 << rn2(4);
dpos = dd->pos;
/* Convert wall and pos into an absolute coordinate! */
wtry = rn2(4);
switch (wtry) {
case 0:
if (!(dwall & W_NORTH))
goto redoloop;
y = broom->ly - 1;
x = broom->lx
+ ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos);
if (IS_ROCK(levl[x][y - 1].typ))
goto redoloop;
goto outdirloop;
case 1:
if (!(dwall & W_SOUTH))
goto redoloop;
y = broom->hy + 1;
x = broom->lx
+ ((dpos == -1) ? rn2(1 + (broom->hx - broom->lx)) : dpos);
if (IS_ROCK(levl[x][y + 1].typ))
goto redoloop;
goto outdirloop;
case 2:
if (!(dwall & W_WEST))
goto redoloop;
x = broom->lx - 1;
y = broom->ly
+ ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos);
if (IS_ROCK(levl[x - 1][y].typ))
goto redoloop;
goto outdirloop;
case 3:
if (!(dwall & W_EAST))
goto redoloop;
x = broom->hx + 1;
y = broom->ly
+ ((dpos == -1) ? rn2(1 + (broom->hy - broom->ly)) : dpos);
if (IS_ROCK(levl[x + 1][y].typ))
goto redoloop;
goto outdirloop;
default:
x = y = 0;
panic("create_door: No wall for door!");
goto outdirloop;
}
outdirloop:
if (okdoor(x, y))
break;
redoloop:
;
} while (++trycnt <= 100);
if (trycnt > 100) {
impossible("create_door: Can't find a proper place!");
return;
}
levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
levl[x][y].doormask = dd->mask;
}
create_secret_door
/*
* Create a secret door in croom on any one of the specified walls.
*/
void
create_secret_door(croom, walls)
struct mkroom *croom;
xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
{
xchar sx, sy; /* location of the secret door */
int count;
for (count = 0; count < 100; count++) {
sx = rn1(croom->hx - croom->lx + 1, croom->lx);
sy = rn1(croom->hy - croom->ly + 1, croom->ly);
switch (rn2(4)) {
case 0: /* top */
if (!(walls & W_NORTH))
continue;
sy = croom->ly - 1;
break;
case 1: /* bottom */
if (!(walls & W_SOUTH))
continue;
sy = croom->hy + 1;
break;
case 2: /* left */
if (!(walls & W_EAST))
continue;
sx = croom->lx - 1;
break;
case 3: /* right */
if (!(walls & W_WEST))
continue;
sx = croom->hx + 1;
break;
}
if (okdoor(sx, sy)) {
levl[sx][sy].typ = SDOOR;
levl[sx][sy].doormask = D_CLOSED;
return;
}
}
impossible("couldn't create secret door on any walls 0x%x", walls);
}
create_trap
/*
* Create a trap in a room.
*/
STATIC_OVL void
create_trap(t, croom)
spltrap *t;
struct mkroom *croom;
{
schar x = -1, y = -1;
coord tm;
if (croom)
get_free_room_loc(&x, &y, croom, t->coord);
else {
int trycnt = 0;
do {
get_location_coord(&x, &y, DRY, croom, t->coord);
} while ((levl[x][y].typ == STAIRS || levl[x][y].typ == LADDER)
&& ++trycnt <= 100);
if (trycnt > 100)
return;
}
tm.x = x;
tm.y = y;
mktrap(t->type, 1, (struct mkroom *) 0, &tm);
}
noncoalignment
/*
* Create a monster in a room.
*/
STATIC_OVL int
noncoalignment(alignment)
aligntyp alignment;
{
int k;
k = rn2(2);
if (!alignment)
return (k ? -1 : 1);
return (k ? -alignment : 0);
}
m_bad_boulder_spot
/* attempt to screen out locations where a mimic-as-boulder shouldn't occur */
STATIC_OVL boolean
m_bad_boulder_spot(x, y)
int x, y;
{
struct rm *lev;
/* avoid trap locations */
if (t_at(x, y))
return TRUE;
/* try to avoid locations which already have a boulder (this won't
actually work; we get called before objects have been placed...) */
if (sobj_at(BOULDER, x, y))
return TRUE;
/* avoid closed doors */
lev = &levl[x][y];
if (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED | D_LOCKED)) != 0)
return TRUE;
/* spot is ok */
return FALSE;
}
pm_to_humidity
STATIC_OVL int
pm_to_humidity(pm)
struct permonst *pm;
{
int loc = DRY;
if (!pm)
return loc;
if (pm->mlet == S_EEL || amphibious(pm) || is_swimmer(pm))
loc = WET;
if (is_flyer(pm) || is_floater(pm))
loc |= (HOT | WET);
if (passes_walls(pm) || noncorporeal(pm))
loc |= SOLID;
if (flaming(pm))
loc |= HOT;
return loc;
}
create_monster
STATIC_OVL void
create_monster(m, croom)
monster *m;
struct mkroom *croom;
{
struct monst *mtmp;
schar x, y;
char class;
aligntyp amask;
coord cc;
struct permonst *pm;
unsigned g_mvflags;
if (m->class >= 0)
class = (char) def_char_to_monclass((char) m->class);
else
class = 0;
if (class == MAXMCLASSES)
panic("create_monster: unknown monster class '%c'", m->class);
amask = (m->align == AM_SPLEV_CO)
? Align2amask(u.ualignbase[A_ORIGINAL])
: (m->align == AM_SPLEV_NONCO)
? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL]))
: (m->align <= -(MAX_REGISTERS + 1))
? induced_align(80)
: (m->align < 0 ? ralign[-m->align - 1] : m->align);
if (!class)
pm = (struct permonst *) 0;
else if (m->id != NON_PM) {
pm = &mons[m->id];
g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags;
if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT))
return;
else if (g_mvflags & G_GONE) /* genocided or extinct */
pm = (struct permonst *) 0; /* make random monster */
} else {
pm = mkclass(class, G_NOGEN);
/* if we can't get a specific monster type (pm == 0) then the
class has been genocided, so settle for a random monster */
}
if (In_mines(&u.uz) && pm && your_race(pm)
&& (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3))
pm = (struct permonst *) 0;
if (pm) {
int loc = pm_to_humidity(pm);
/* If water-liking monster, first try is without DRY */
get_location_coord(&x, &y, loc | NO_LOC_WARN, croom, m->coord);
if (x == -1 && y == -1) {
loc |= DRY;
get_location_coord(&x, &y, loc, croom, m->coord);
}
} else {
get_location_coord(&x, &y, DRY, croom, m->coord);
}
/* try to find a close place if someone else is already there */
if (MON_AT(x, y) && enexto(&cc, x, y, pm))
x = cc.x, y = cc.y;
if (m->align != -(MAX_REGISTERS + 2))
mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful);
else if (PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD)
mtmp = mk_mplayer(pm, x, y, FALSE);
else
mtmp = makemon(pm, x, y, NO_MM_FLAGS);
if (mtmp) {
x = mtmp->mx, y = mtmp->my; /* sanity precaution */
m->x = x, m->y = y;
/* handle specific attributes for some special monsters */
if (m->name.str)
mtmp = christen_monst(mtmp, m->name.str);
/*
* This doesn't complain if an attempt is made to give a
* non-mimic/non-shapechanger an appearance or to give a
* shapechanger a non-monster shape, it just refuses to comply.
*/
if (m->appear_as.str
&& ((mtmp->data->mlet == S_MIMIC)
/* shapechanger (chameleons, et al, and vampires) */
|| (mtmp->cham >= LOW_PM && m->appear == M_AP_MONSTER))
&& !Protection_from_shape_changers) {
int i;
switch (m->appear) {
case M_AP_NOTHING:
impossible(
"create_monster: mon has an appearance, \"%s\", but no type",
m->appear_as.str);
break;
case M_AP_FURNITURE:
for (i = 0; i < MAXPCHARS; i++)
if (!strcmp(defsyms[i].explanation, m->appear_as.str))
break;
if (i == MAXPCHARS) {
impossible("create_monster: can't find feature \"%s\"",
m->appear_as.str);
} else {
mtmp->m_ap_type = M_AP_FURNITURE;
mtmp->mappearance = i;
}
break;
case M_AP_OBJECT:
for (i = 0; i < NUM_OBJECTS; i++)
if (OBJ_NAME(objects[i])
&& !strcmp(OBJ_NAME(objects[i]), m->appear_as.str))
break;
if (i == NUM_OBJECTS) {
impossible("create_monster: can't find object \"%s\"",
m->appear_as.str);
} else {
mtmp->m_ap_type = M_AP_OBJECT;
mtmp->mappearance = i;
/* try to avoid placing mimic boulder on a trap */
if (i == BOULDER && m->x < 0
&& m_bad_boulder_spot(x, y)) {
int retrylimit = 10;
remove_monster(x, y);
do {
x = m->x;
y = m->y;
get_location(&x, &y, DRY, croom);
if (MON_AT(x, y) && enexto(&cc, x, y, pm))
x = cc.x, y = cc.y;
} while (m_bad_boulder_spot(x, y)
&& --retrylimit > 0);
place_monster(mtmp, x, y);
/* if we didn't find a good spot
then mimic something else */
if (!retrylimit)
set_mimic_sym(mtmp);
}
}
break;
case M_AP_MONSTER: {
int mndx;
if (!strcmpi(m->appear_as.str, "random"))
mndx = select_newcham_form(mtmp);
else
mndx = name_to_mon(m->appear_as.str);
if (mndx == NON_PM || (is_vampshifter(mtmp)
&& !validvamp(mtmp, &mndx, S_HUMAN))) {
impossible("create_monster: invalid %s (\"%s\")",
(mtmp->data->mlet == S_MIMIC)
? "mimic appearance"
: (mtmp->data == &mons[PM_WIZARD_OF_YENDOR])
? "Wizard appearance"
: is_vampshifter(mtmp)
? "vampire shape"
: "chameleon shape",
m->appear_as.str);
} else if (&mons[mndx] == mtmp->data) {
/* explicitly forcing a mimic to appear as itself */
mtmp->m_ap_type = M_AP_NOTHING;
mtmp->mappearance = 0;
} else if (mtmp->data->mlet == S_MIMIC
|| mtmp->data == &mons[PM_WIZARD_OF_YENDOR]) {
/* this is ordinarily only used for Wizard clones
and hasn't been exhaustively tested for mimics */
mtmp->m_ap_type = M_AP_MONSTER;
mtmp->mappearance = mndx;
} else { /* chameleon or vampire */
struct permonst *mdat = &mons[mndx];
struct permonst *olddata = mtmp->data;
mgender_from_permonst(mtmp, mdat);
set_mon_data(mtmp, mdat, 0);
if (emits_light(olddata) != emits_light(mtmp->data)) {
/* used to give light, now doesn't, or vice versa,
or light's range has changed */
if (emits_light(olddata))
del_light_source(LS_MONSTER, (genericptr_t) mtmp);
if (emits_light(mtmp->data))
new_light_source(mtmp->mx, mtmp->my,
emits_light(mtmp->data),
LS_MONSTER, (genericptr_t) mtmp);
}
if (!mtmp->perminvis || pm_invisible(olddata))
mtmp->perminvis = pm_invisible(mdat);
}
break;
}
default:
impossible(
"create_monster: unimplemented mon appear type [%d,\"%s\"]",
m->appear, m->appear_as.str);
break;
}
if (does_block(x, y, &levl[x][y]))
block_point(x, y);
}
if (m->peaceful >= 0) {
mtmp->mpeaceful = m->peaceful;
/* changed mpeaceful again; have to reset malign */
set_malign(mtmp);
}
if (m->asleep >= 0) {
#ifdef UNIXPC
/* optimizer bug strikes again */
if (m->asleep)
mtmp->msleeping = 1;
else
mtmp->msleeping = 0;
#else
mtmp->msleeping = m->asleep;
#endif
}
if (m->seentraps)
mtmp->mtrapseen = m->seentraps;
if (m->female)
mtmp->female = 1;
if (m->cancelled)
mtmp->mcan = 1;
if (m->revived)
mtmp->mrevived = 1;
if (m->avenge)
mtmp->mavenge = 1;
if (m->stunned)
mtmp->mstun = 1;
if (m->confused)
mtmp->mconf = 1;
if (m->invis) {
mtmp->minvis = mtmp->perminvis = 1;
}
if (m->blinded) {
mtmp->mcansee = 0;
mtmp->mblinded = (m->blinded % 127);
}
if (m->paralyzed) {
mtmp->mcanmove = 0;
mtmp->mfrozen = (m->paralyzed % 127);
}
if (m->fleeing) {
mtmp->mflee = 1;
mtmp->mfleetim = (m->fleeing % 127);
}
if (m->has_invent) {
discard_minvent(mtmp);
invent_carrying_monster = mtmp;
}
}
}
create_object
/*
* Create an object in a room.
*/
STATIC_OVL void
create_object(o, croom)
object *o;
struct mkroom *croom;
{
struct obj *otmp;
schar x, y;
char c;
boolean named; /* has a name been supplied in level description? */
named = o->name.str ? TRUE : FALSE;
get_location_coord(&x, &y, DRY, croom, o->coord);
if (o->class >= 0)
c = o->class;
else
c = 0;
if (!c)
otmp = mkobj_at(RANDOM_CLASS, x, y, !named);
else if (o->id != -1)
otmp = mksobj_at(o->id, x, y, TRUE, !named);
else {
/*
* The special levels are compiled with the default "text" object
* class characters. We must convert them to the internal format.
*/
char oclass = (char) def_char_to_objclass(c);
if (oclass == MAXOCLASSES)
panic("create_object: unexpected object class '%c'", c);
/* KMH -- Create piles of gold properly */
if (oclass == COIN_CLASS)
otmp = mkgold(0L, x, y);
else
otmp = mkobj_at(oclass, x, y, !named);
}
if (o->spe != -127) /* That means NOT RANDOM! */
otmp->spe = (schar) o->spe;
switch (o->curse_state) {
case 1:
bless(otmp);
break; /* BLESSED */
case 2:
unbless(otmp);
uncurse(otmp);
break; /* uncursed */
case 3:
curse(otmp);
break; /* CURSED */
default:
break; /* Otherwise it's random and we're happy
* with what mkobj gave us! */
}
/* corpsenm is "empty" if -1, random if -2, otherwise specific */
if (o->corpsenm != NON_PM) {
if (o->corpsenm == NON_PM - 1)
set_corpsenm(otmp, rndmonnum());
else
set_corpsenm(otmp, o->corpsenm);
}
/* set_corpsenm() took care of egg hatch and corpse timers */
if (named)
otmp = oname(otmp, o->name.str);
if (o->eroded) {
if (o->eroded < 0) {
otmp->oerodeproof = 1;
} else {
otmp->oeroded = (o->eroded % 4);
otmp->oeroded2 = ((o->eroded >> 2) % 4);
}
}
if (o->recharged)
otmp->recharged = (o->recharged % 8);
if (o->locked) {
otmp->olocked = 1;
} else if (o->broken) {
otmp->obroken = 1;
otmp->olocked = 0; /* obj generation may set */
}
if (o->trapped == 0 || o->trapped == 1)
otmp->otrapped = o->trapped;
if (o->greased)
otmp->greased = 1;
#ifdef INVISIBLE_OBJECTS
if (o->invis)
otmp->oinvis = 1;
#endif
if (o->quan > 0 && objects[otmp->otyp].oc_merge) {
otmp->quan = o->quan;
otmp->owt = weight(otmp);
}
/* contents */
if (o->containment & SP_OBJ_CONTENT) {
if (!container_idx) {
if (!invent_carrying_monster) {
/*impossible("create_object: no container");*/
/* don't complain, the monster may be gone legally
(eg. unique demon already generated)
TODO: In the case of unique demon lords, they should
get their inventories even when they get generated
outside the des-file. Maybe another data file that
determines what inventories monsters get by default?
*/
} else {
int ci;
struct obj *objcheck = otmp;
int inuse = -1;
for (ci = 0; ci < container_idx; ci++)
if (container_obj[ci] == objcheck)
inuse = ci;
remove_object(otmp);
if (mpickobj(invent_carrying_monster, otmp)) {
if (inuse > -1) {
impossible(
"container given to monster was merged or deallocated.");
for (ci = inuse; ci < container_idx - 1; ci++)
container_obj[ci] = container_obj[ci + 1];
container_obj[container_idx] = NULL;
container_idx--;
}
/* we lost track of it. */
return;
}
}
} else {
struct obj *cobj = container_obj[container_idx - 1];
remove_object(otmp);
if (cobj) {
(void) add_to_container(cobj, otmp);
cobj->owt = weight(cobj);
} else {
obj_extract_self(otmp);
obfree(otmp, NULL);
return;
}
}
}
/* container */
if (o->containment & SP_OBJ_CONTAINER) {
delete_contents(otmp);
if (container_idx < MAX_CONTAINMENT) {
container_obj[container_idx] = otmp;
container_idx++;
} else
impossible("create_object: too deeply nested containers.");
}
/* Medusa level special case: statues are petrified monsters, so they
* are not stone-resistant and have monster inventory. They also lack
* other contents, but that can be specified as an empty container.
*/
if (o->id == STATUE && Is_medusa_level(&u.uz) && o->corpsenm == NON_PM) {
struct monst *was;
struct obj *obj;
int wastyp;
int i = 0; /* prevent endless loop in case makemon always fails */
/* Named random statues are of player types, and aren't stone-
* resistant (if they were, we'd have to reset the name as well as
* setting corpsenm).
*/
for (wastyp = otmp->corpsenm; i < 1000; i++, wastyp = rndmonnum()) {
/* makemon without rndmonst() might create a group */
was = makemon(&mons[wastyp], 0, 0, MM_NOCOUNTBIRTH);
if (was) {
if (!resists_ston(was)) {
(void) propagate(wastyp, TRUE, FALSE);
break;
}
mongone(was);
was = NULL;
}
}
if (was) {
set_corpsenm(otmp, wastyp);
while (was->minvent) {
obj = was->minvent;
obj->owornmask = 0;
obj_extract_self(obj);
(void) add_to_container(otmp, obj);
}
otmp->owt = weight(otmp);
mongone(was);
}
}
if (o->id != -1) {
static const char prize_warning[] = "multiple prizes on %s level";
/* if this is a specific item of the right type and it is being
created on the right level, flag it as the designated item
used to detect a special achievement (to whit, reaching and
exploring the target level, although the exploration part
might be short-circuited if a monster brings object to hero) */
if (Is_mineend_level(&u.uz)) {
if (otmp->otyp == iflags.mines_prize_type) {
otmp->record_achieve_special = MINES_PRIZE;
if (++mines_prize_count > 1)
impossible(prize_warning, "mines end");
}
} else if (Is_sokoend_level(&u.uz)) {
if (otmp->otyp == iflags.soko_prize_type1) {
otmp->record_achieve_special = SOKO_PRIZE1;
if (++soko_prize_count > 1)
impossible(prize_warning, "sokoban end");
} else if (otmp->otyp == iflags.soko_prize_type2) {
otmp->record_achieve_special = SOKO_PRIZE2;
if (++soko_prize_count > 1)
impossible(prize_warning, "sokoban end");
}
}
}
stackobj(otmp);
if (o->lit) {
begin_burn(otmp, FALSE);
}
if (o->buried) {
boolean dealloced;
(void) bury_an_obj(otmp, &dealloced);
if (dealloced && container_idx) {
container_obj[container_idx - 1] = NULL;
}
}
}
create_altar
/*
* Create an altar in a room.
*/
STATIC_OVL void
create_altar(a, croom)
altar *a;
struct mkroom *croom;
{
schar sproom, x = -1, y = -1;
aligntyp amask;
boolean croom_is_temple = TRUE;
int oldtyp;
if (croom) {
get_free_room_loc(&x, &y, croom, a->coord);
if (croom->rtype != TEMPLE)
croom_is_temple = FALSE;
} else {
get_location_coord(&x, &y, DRY, croom, a->coord);
if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
croom = &rooms[sproom - ROOMOFFSET];
else
croom_is_temple = FALSE;
}
/* check for existing features */
oldtyp = levl[x][y].typ;
if (oldtyp == STAIRS || oldtyp == LADDER)
return;
/* Is the alignment random ?
* If so, it's an 80% chance that the altar will be co-aligned.
*
* The alignment is encoded as amask values instead of alignment
* values to avoid conflicting with the rest of the encoding,
* shared by many other parts of the special level code.
*/
amask = (a->align == AM_SPLEV_CO)
? Align2amask(u.ualignbase[A_ORIGINAL])
: (a->align == AM_SPLEV_NONCO)
? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL]))
: (a->align == -(MAX_REGISTERS + 1))
? induced_align(80)
: (a->align < 0 ? ralign[-a->align - 1] : a->align);
levl[x][y].typ = ALTAR;
levl[x][y].altarmask = amask;
if (a->shrine < 0)
a->shrine = rn2(2); /* handle random case */
if (!croom_is_temple || !a->shrine)
return;
if (a->shrine) { /* Is it a shrine or sanctum? */
priestini(&u.uz, croom, x, y, (a->shrine > 1));
levl[x][y].altarmask |= AM_SHRINE;
level.flags.has_temple = TRUE;
}
}
replace_terrain
void
replace_terrain(terr, croom)
replaceterrain *terr;
struct mkroom *croom;
{
schar x, y, x1, y1, x2, y2;
if (terr->toter >= MAX_TYPE)
return;
x1 = terr->x1;
y1 = terr->y1;
get_location(&x1, &y1, ANY_LOC, croom);
x2 = terr->x2;
y2 = terr->y2;
get_location(&x2, &y2, ANY_LOC, croom);
for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++)
for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++)
if (levl[x][y].typ == terr->fromter && rn2(100) < terr->chance) {
SET_TYPLIT(x, y, terr->toter, terr->tolit);
}
}
search_door
/*
* Search for a door in a room on a specified wall.
*/
STATIC_OVL boolean
search_door(croom, x, y, wall, cnt)
struct mkroom *croom;
xchar *x, *y;
xchar wall;
int cnt;
{
int dx, dy;
int xx, yy;
switch (wall) {
case W_NORTH:
dy = 0;
dx = 1;
xx = croom->lx;
yy = croom->hy + 1;
break;
case W_SOUTH:
dy = 0;
dx = 1;
xx = croom->lx;
yy = croom->ly - 1;
break;
case W_EAST:
dy = 1;
dx = 0;
xx = croom->hx + 1;
yy = croom->ly;
break;
case W_WEST:
dy = 1;
dx = 0;
xx = croom->lx - 1;
yy = croom->ly;
break;
default:
dx = dy = xx = yy = 0;
panic("search_door: Bad wall!");
break;
}
while (xx <= croom->hx + 1 && yy <= croom->hy + 1) {
if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
*x = xx;
*y = yy;
if (cnt-- <= 0)
return TRUE;
}
xx += dx;
yy += dy;
}
return FALSE;
}
dig_corridor
/*
* Dig a corridor between two points.
*/
boolean
dig_corridor(org, dest, nxcor, ftyp, btyp)
coord *org, *dest;
boolean nxcor;
schar ftyp, btyp;
{
int dx = 0, dy = 0, dix, diy, cct;
struct rm *crm;
int tx, ty, xx, yy;
xx = org->x;
yy = org->y;
tx = dest->x;
ty = dest->y;
if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 || xx > COLNO - 1
|| tx > COLNO - 1 || yy > ROWNO - 1 || ty > ROWNO - 1) {
debugpline4("dig_corridor: bad coords <%d,%d> <%d,%d>.",
xx, yy, tx, ty);
return FALSE;
}
if (tx > xx)
dx = 1;
else if (ty > yy)
dy = 1;
else if (tx < xx)
dx = -1;
else
dy = -1;
xx -= dx;
yy -= dy;
cct = 0;
while (xx != tx || yy != ty) {
/* loop: dig corridor at [xx,yy] and find new [xx,yy] */
if (cct++ > 500 || (nxcor && !rn2(35)))
return FALSE;
xx += dx;
yy += dy;
if (xx >= COLNO - 1 || xx <= 0 || yy <= 0 || yy >= ROWNO - 1)
return FALSE; /* impossible */
crm = &levl[xx][yy];
if (crm->typ == btyp) {
if (ftyp != CORR || rn2(100)) {
crm->typ = ftyp;
if (nxcor && !rn2(50))
(void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
} else {
crm->typ = SCORR;
}
} else if (crm->typ != ftyp && crm->typ != SCORR) {
/* strange ... */
return FALSE;
}
/* find next corridor position */
dix = abs(xx - tx);
diy = abs(yy - ty);
if ((dix > diy) && diy && !rn2(dix-diy+1)) {
dix = 0;
} else if ((diy > dix) && dix && !rn2(diy-dix+1)) {
diy = 0;
}
/* do we have to change direction ? */
if (dy && dix > diy) {
register int ddx = (xx > tx) ? -1 : 1;
crm = &levl[xx + ddx][yy];
if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
dx = ddx;
dy = 0;
continue;
}
} else if (dx && diy > dix) {
register int ddy = (yy > ty) ? -1 : 1;
crm = &levl[xx][yy + ddy];
if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
dy = ddy;
dx = 0;
continue;
}
}
/* continue straight on? */
crm = &levl[xx + dx][yy + dy];
if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
continue;
/* no, what must we do now?? */
if (dx) {
dx = 0;
dy = (ty < yy) ? -1 : 1;
} else {
dy = 0;
dx = (tx < xx) ? -1 : 1;
}
crm = &levl[xx + dx][yy + dy];
if (crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
continue;
dy = -dy;
dx = -dx;
}
return TRUE;
}
fix_stair_rooms
/*
* Disgusting hack: since special levels have their rooms filled before
* sorting the rooms, we have to re-arrange the speed values upstairs_room
* and dnstairs_room after the rooms have been sorted. On normal levels,
* stairs don't get created until _after_ sorting takes place.
*/
STATIC_OVL void
fix_stair_rooms()
{
int i;
struct mkroom *croom;
if (xdnstair
&& !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx)
&& (dnstairs_room->ly <= ydnstair
&& ydnstair <= dnstairs_room->hy))) {
for (i = 0; i < nroom; i++) {
croom = &rooms[i];
if ((croom->lx <= xdnstair && xdnstair <= croom->hx)
&& (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
dnstairs_room = croom;
break;
}
}
if (i == nroom)
panic("Couldn't find dnstair room in fix_stair_rooms!");
}
if (xupstair
&& !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx)
&& (upstairs_room->ly <= yupstair
&& yupstair <= upstairs_room->hy))) {
for (i = 0; i < nroom; i++) {
croom = &rooms[i];
if ((croom->lx <= xupstair && xupstair <= croom->hx)
&& (croom->ly <= yupstair && yupstair <= croom->hy)) {
upstairs_room = croom;
break;
}
}
if (i == nroom)
panic("Couldn't find upstair room in fix_stair_rooms!");
}
}
create_corridor
/*
* Corridors always start from a door. But it can end anywhere...
* Basically we search for door coordinates or for endpoints coordinates
* (from a distance).
*/
STATIC_OVL void
create_corridor(c)
corridor *c;
{
coord org, dest;
if (c->src.room == -1) {
fix_stair_rooms();
makecorridors(); /*makecorridors(c->src.door);*/
return;
}
if (!search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
c->src.door))
return;
if (c->dest.room != -1) {
if (!search_door(&rooms[c->dest.room], &dest.x, &dest.y, c->dest.wall,
c->dest.door))
return;
switch (c->src.wall) {
case W_NORTH:
org.y--;
break;
case W_SOUTH:
org.y++;
break;
case W_WEST:
org.x--;
break;
case W_EAST:
org.x++;
break;
}
switch (c->dest.wall) {
case W_NORTH:
dest.y--;
break;
case W_SOUTH:
dest.y++;
break;
case W_WEST:
dest.x--;
break;
case W_EAST:
dest.x++;
break;
}
(void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
}
}
fill_room
/*
* Fill a room (shop, zoo, etc...) with appropriate stuff.
*/
void
fill_room(croom, prefilled)
struct mkroom *croom;
boolean prefilled;
{
if (!croom || croom->rtype == OROOM)
return;
if (!prefilled) {
int x, y;
/* Shop ? */
if (croom->rtype >= SHOPBASE) {
stock_room(croom->rtype - SHOPBASE, croom);
level.flags.has_shop = TRUE;
return;
}
switch (croom->rtype) {
case VAULT:
for (x = croom->lx; x <= croom->hx; x++)
for (y = croom->ly; y <= croom->hy; y++)
(void) mkgold((long) rn1(abs(depth(&u.uz)) * 100, 51),
x, y);
break;
case COURT:
case ZOO:
case BEEHIVE:
case MORGUE:
case BARRACKS:
fill_zoo(croom);
break;
}
}
switch (croom->rtype) {
case VAULT:
level.flags.has_vault = TRUE;
break;
case ZOO:
level.flags.has_zoo = TRUE;
break;
case COURT:
level.flags.has_court = TRUE;
break;
case MORGUE:
level.flags.has_morgue = TRUE;
break;
case BEEHIVE:
level.flags.has_beehive = TRUE;
break;
case BARRACKS:
level.flags.has_barracks = TRUE;
break;
case TEMPLE:
level.flags.has_temple = TRUE;
break;
case SWAMP:
level.flags.has_swamp = TRUE;
break;
}
}
build_room
struct mkroom *
build_room(r, mkr)
room *r;
struct mkroom *mkr;
{
boolean okroom;
struct mkroom *aroom;
xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
if (mkr) {
aroom = &subrooms[nsubroom];
okroom = create_subroom(mkr, r->x, r->y, r->w, r->h, rtype, r->rlit);
} else {
aroom = &rooms[nroom];
okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, r->yalign,
rtype, r->rlit);
}
if (okroom) {
#ifdef SPECIALIZATION
topologize(aroom, FALSE); /* set roomno */
#else
topologize(aroom); /* set roomno */
#endif
aroom->needfill = r->filled;
aroom->needjoining = r->joined;
return aroom;
}
return (struct mkroom *) 0;
}
light_region
/*
* set lighting in a region that will not become a room.
*/
STATIC_OVL void
light_region(tmpregion)
region *tmpregion;
{
register boolean litstate = tmpregion->rlit ? 1 : 0;
register int hiy = tmpregion->y2;
register int x, y;
register struct rm *lev;
int lowy = tmpregion->y1;
int lowx = tmpregion->x1, hix = tmpregion->x2;
if (litstate) {
/* adjust region size for walls, but only if lighted */
lowx = max(lowx - 1, 1);
hix = min(hix + 1, COLNO - 1);
lowy = max(lowy - 1, 0);
hiy = min(hiy + 1, ROWNO - 1);
}
for (x = lowx; x <= hix; x++) {
lev = &levl[x][lowy];
for (y = lowy; y <= hiy; y++) {
if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
lev->lit = litstate;
lev++;
}
}
}
wallify_map
void
wallify_map(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
for (y = y1; y <= y2; y++) {
lo_yy = (y > 0) ? y - 1 : 0;
hi_yy = (y < y2) ? y + 1 : y2;
for (x = x1; x <= x2; x++) {
if (levl[x][y].typ != STONE)
continue;
lo_xx = (x > 0) ? x - 1 : 0;
hi_xx = (x < x2) ? x + 1 : x2;
for (yy = lo_yy; yy <= hi_yy; yy++)
for (xx = lo_xx; xx <= hi_xx; xx++)
if (IS_ROOM(levl[xx][yy].typ)
|| levl[xx][yy].typ == CROSSWALL) {
levl[x][y].typ = (yy != y) ? HWALL : VWALL;
yy = hi_yy; /* end `yy' loop */
break; /* end `xx' loop */
}
}
}
}
maze1xy
/*
* Select a random coordinate in the maze.
*
* We want a place not 'touched' by the loader. That is, a place in
* the maze outside every part of the special level.
*/
STATIC_OVL void
maze1xy(m, humidity)
coord *m;
int humidity;
{
register int x, y, tryct = 2000;
/* tryct: normally it won't take more than ten or so tries due
to the circumstances under which we'll be called, but the
`humidity' screening might drastically change the chances */
do {
x = rn1(x_maze_max - 3, 3);
y = rn1(y_maze_max - 3, 3);
if (--tryct < 0)
break; /* give up */
} while (!(x % 2) || !(y % 2) || SpLev_Map[x][y]
|| !is_ok_location((schar) x, (schar) y, humidity));
m->x = (xchar) x, m->y = (xchar) y;
}
fill_empty_maze
/*
* If there's a significant portion of maze unused by the special level,
* we don't want it empty.
*
* Makes the number of traps, monsters, etc. proportional
* to the size of the maze.
*/
STATIC_OVL void
fill_empty_maze()
{
int mapcountmax, mapcount, mapfact;
xchar x, y;
coord mm;
mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
mapcountmax = mapcountmax / 2;
for (x = 2; x < x_maze_max; x++)
for (y = 0; y < y_maze_max; y++)
if (SpLev_Map[x][y])
mapcount--;
if ((mapcount > (int) (mapcountmax / 10))) {
mapfact = (int) ((mapcount * 100L) / mapcountmax);
for (x = rnd((int) (20 * mapfact) / 100); x; x--) {
maze1xy(&mm, DRY);
(void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS, mm.x, mm.y,
TRUE);
}
for (x = rnd((int) (12 * mapfact) / 100); x; x--) {
maze1xy(&mm, DRY);
(void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
}
for (x = rn2(2); x; x--) {
maze1xy(&mm, DRY);
(void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
}
for (x = rnd((int) (12 * mapfact) / 100); x; x--) {
maze1xy(&mm, DRY);
(void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
}
for (x = rn2((int) (15 * mapfact) / 100); x; x--) {
maze1xy(&mm, DRY);
(void) mkgold(0L, mm.x, mm.y);
}
for (x = rn2((int) (15 * mapfact) / 100); x; x--) {
int trytrap;
maze1xy(&mm, DRY);
trytrap = rndtrap();
if (sobj_at(BOULDER, mm.x, mm.y))
while (trytrap == PIT || trytrap == SPIKED_PIT
|| trytrap == TRAPDOOR || trytrap == HOLE)
trytrap = rndtrap();
(void) maketrap(mm.x, mm.y, trytrap);
}
}
}
sp_level_loader
/*
* special level loader
*/
STATIC_OVL boolean
sp_level_loader(fd, lvl)
dlb *fd;
sp_lev *lvl;
{
long n_opcode = 0;
struct opvar *opdat;
int opcode;
Fread((genericptr_t) & (lvl->n_opcodes), 1, sizeof(lvl->n_opcodes), fd);
lvl->opcodes = (_opcode *) alloc(sizeof(_opcode) * (lvl->n_opcodes));
while (n_opcode < lvl->n_opcodes) {
Fread((genericptr_t) &lvl->opcodes[n_opcode].opcode, 1,
sizeof(lvl->opcodes[n_opcode].opcode), fd);
opcode = lvl->opcodes[n_opcode].opcode;
opdat = NULL;
if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES)
panic("sp_level_loader: impossible opcode %i.", opcode);
if (opcode == SPO_PUSH) {
int nsize;
struct opvar *ov = (struct opvar *) alloc(sizeof(struct opvar));
opdat = ov;
ov->spovartyp = SPO_NULL;
ov->vardata.l = 0;
Fread((genericptr_t) & (ov->spovartyp), 1, sizeof(ov->spovartyp),
fd);
switch (ov->spovartyp) {
case SPOVAR_NULL:
break;
case SPOVAR_COORD:
case SPOVAR_REGION:
case SPOVAR_MAPCHAR:
case SPOVAR_MONST:
case SPOVAR_OBJ:
case SPOVAR_INT:
Fread((genericptr_t) & (ov->vardata.l), 1,
sizeof(ov->vardata.l), fd);
break;
case SPOVAR_VARIABLE:
case SPOVAR_STRING:
case SPOVAR_SEL: {
char *opd;
Fread((genericptr_t) &nsize, 1, sizeof(nsize), fd);
opd = (char *) alloc(nsize + 1);
if (nsize)
Fread(opd, 1, nsize, fd);
opd[nsize] = 0;
ov->vardata.str = opd;
break;
}
default:
panic("sp_level_loader: unknown opvar type %i",
ov->spovartyp);
}
}
lvl->opcodes[n_opcode].opdat = opdat;
n_opcode++;
} /*while*/
return TRUE;
}
sp_level_free
/* Frees the memory allocated for special level creation structs */
STATIC_OVL boolean
sp_level_free(lvl)
sp_lev *lvl;
{
static const char nhFunc[] = "sp_level_free";
long n_opcode = 0;
while (n_opcode < lvl->n_opcodes) {
int opcode = lvl->opcodes[n_opcode].opcode;
struct opvar *opdat = lvl->opcodes[n_opcode].opdat;
if (opcode < SPO_NULL || opcode >= MAX_SP_OPCODES)
panic("sp_level_free: unknown opcode %i", opcode);
if (opdat)
opvar_free(opdat);
n_opcode++;
}
Free(lvl->opcodes);
lvl->opcodes = NULL;
return TRUE;
}
splev_initlev
void
splev_initlev(linit)
lev_init *linit;
{
switch (linit->init_style) {
default:
impossible("Unrecognized level init style.");
break;
case LVLINIT_NONE:
break;
case LVLINIT_SOLIDFILL:
if (linit->lit == -1)
linit->lit = rn2(2);
lvlfill_solid(linit->filling, linit->lit);
break;
case LVLINIT_MAZEGRID:
lvlfill_maze_grid(2, 0, x_maze_max, y_maze_max, linit->filling);
break;
case LVLINIT_ROGUE:
makeroguerooms();
break;
case LVLINIT_MINES:
if (linit->lit == -1)
linit->lit = rn2(2);
if (linit->filling > -1)
lvlfill_solid(linit->filling, 0);
linit->icedpools = icedpools;
mkmap(linit);
break;
}
}
frame_new
struct sp_frame *
frame_new(execptr)
long execptr;
{
struct sp_frame *frame =
(struct sp_frame *) alloc(sizeof(struct sp_frame));
frame->next = NULL;
frame->variables = NULL;
frame->n_opcode = execptr;
frame->stack = (struct splevstack *) alloc(sizeof(struct splevstack));
splev_stack_init(frame->stack);
return frame;
}
frame_del
void
frame_del(frame)
struct sp_frame *frame;
{
if (!frame)
return;
if (frame->stack) {
splev_stack_done(frame->stack);
frame->stack = NULL;
}
if (frame->variables) {
variable_list_del(frame->variables);
frame->variables = NULL;
}
Free(frame);
}
spo_frame_push
void
spo_frame_push(coder)
struct sp_coder *coder;
{
struct sp_frame *tmpframe = frame_new(coder->frame->n_opcode);
tmpframe->next = coder->frame;
coder->frame = tmpframe;
}
spo_frame_pop
void
spo_frame_pop(coder)
struct sp_coder *coder;
{
if (coder->frame && coder->frame->next) {
struct sp_frame *tmpframe = coder->frame->next;
frame_del(coder->frame);
coder->frame = tmpframe;
coder->stack = coder->frame->stack;
}
}
sp_code_jmpaddr
long
sp_code_jmpaddr(curpos, jmpaddr)
long curpos, jmpaddr;
{
return (curpos + jmpaddr);
}
spo_call
void
spo_call(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_call";
struct opvar *addr;
struct opvar *params;
struct sp_frame *tmpframe;
if (!OV_pop_i(addr) || !OV_pop_i(params))
return;
if (OV_i(params) < 0)
return;
tmpframe = frame_new(sp_code_jmpaddr(coder->frame->n_opcode,
OV_i(addr) - 1));
while (OV_i(params)-- > 0) {
splev_stack_push(tmpframe->stack, splev_stack_getdat_any(coder));
}
splev_stack_reverse(tmpframe->stack);
/* push a frame */
tmpframe->next = coder->frame;
coder->frame = tmpframe;
opvar_free(addr);
opvar_free(params);
}
spo_return
void
spo_return(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_return";
struct opvar *params;
if (!coder->frame || !coder->frame->next)
panic("return: no frame.");
if (!OV_pop_i(params))
return;
if (OV_i(params) < 0)
return;
while (OV_i(params)-- > 0) {
splev_stack_push(coder->frame->next->stack,
splev_stack_pop(coder->stack));
}
/* pop the frame */
if (coder->frame->next) {
struct sp_frame *tmpframe = coder->frame->next;
frame_del(coder->frame);
coder->frame = tmpframe;
coder->stack = coder->frame->stack;
}
opvar_free(params);
}
/*ARGUSED*/
spo_end_moninvent
void
spo_end_moninvent(coder)
struct sp_coder *coder UNUSED;
{
if (invent_carrying_monster)
m_dowear(invent_carrying_monster, TRUE);
invent_carrying_monster = NULL;
}
/*ARGUSED*/
spo_pop_container
void
spo_pop_container(coder)
struct sp_coder *coder UNUSED;
{
if (container_idx > 0) {
container_idx--;
container_obj[container_idx] = NULL;
}
}
spo_message
void
spo_message(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_message";
struct opvar *op;
char *msg, *levmsg;
int old_n, n;
if (!OV_pop_s(op))
return;
msg = OV_s(op);
if (!msg)
return;
old_n = lev_message ? (strlen(lev_message) + 1) : 0;
n = strlen(msg);
levmsg = (char *) alloc(old_n + n + 1);
if (old_n)
levmsg[old_n - 1] = '\n';
if (lev_message)
(void) memcpy((genericptr_t) levmsg, (genericptr_t) lev_message,
old_n - 1);
(void) memcpy((genericptr_t) &levmsg[old_n], msg, n);
levmsg[old_n + n] = '\0';
Free(lev_message);
lev_message = levmsg;
opvar_free(op);
}
spo_monster
void
spo_monster(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_monster";
int nparams = 0;
struct opvar *varparam;
struct opvar *id, *mcoord, *has_inv;
monster tmpmons;
tmpmons.peaceful = -1;
tmpmons.asleep = -1;
tmpmons.name.str = (char *) 0;
tmpmons.appear = 0;
tmpmons.appear_as.str = (char *) 0;
tmpmons.align = -MAX_REGISTERS - 2;
tmpmons.female = 0;
tmpmons.invis = 0;
tmpmons.cancelled = 0;
tmpmons.revived = 0;
tmpmons.avenge = 0;
tmpmons.fleeing = 0;
tmpmons.blinded = 0;
tmpmons.paralyzed = 0;
tmpmons.stunned = 0;
tmpmons.confused = 0;
tmpmons.seentraps = 0;
tmpmons.has_invent = 0;
if (!OV_pop_i(has_inv))
return;
if (!OV_pop_i(varparam))
return;
while ((nparams++ < (SP_M_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT)
&& (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_M_V_END)) {
struct opvar *parm = NULL;
OV_pop(parm);
switch (OV_i(varparam)) {
case SP_M_V_NAME:
if ((OV_typ(parm) == SPOVAR_STRING) && !tmpmons.name.str)
tmpmons.name.str = dupstr(OV_s(parm));
break;
case SP_M_V_APPEAR:
if ((OV_typ(parm) == SPOVAR_INT) && !tmpmons.appear_as.str) {
tmpmons.appear = OV_i(parm);
opvar_free(parm);
OV_pop(parm);
tmpmons.appear_as.str = dupstr(OV_s(parm));
}
break;
case SP_M_V_ASLEEP:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.asleep = OV_i(parm);
break;
case SP_M_V_ALIGN:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.align = OV_i(parm);
break;
case SP_M_V_PEACEFUL:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.peaceful = OV_i(parm);
break;
case SP_M_V_FEMALE:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.female = OV_i(parm);
break;
case SP_M_V_INVIS:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.invis = OV_i(parm);
break;
case SP_M_V_CANCELLED:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.cancelled = OV_i(parm);
break;
case SP_M_V_REVIVED:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.revived = OV_i(parm);
break;
case SP_M_V_AVENGE:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.avenge = OV_i(parm);
break;
case SP_M_V_FLEEING:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.fleeing = OV_i(parm);
break;
case SP_M_V_BLINDED:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.blinded = OV_i(parm);
break;
case SP_M_V_PARALYZED:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.paralyzed = OV_i(parm);
break;
case SP_M_V_STUNNED:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.stunned = OV_i(parm);
break;
case SP_M_V_CONFUSED:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.confused = OV_i(parm);
break;
case SP_M_V_SEENTRAPS:
if (OV_typ(parm) == SPOVAR_INT)
tmpmons.seentraps = OV_i(parm);
break;
case SP_M_V_END:
nparams = SP_M_V_END + 1;
break;
default:
impossible("MONSTER with unknown variable param type!");
break;
}
opvar_free(parm);
if (OV_i(varparam) != SP_M_V_END) {
opvar_free(varparam);
OV_pop(varparam);
}
}
if (!OV_pop_c(mcoord))
panic("no monster coord?");
if (!OV_pop_typ(id, SPOVAR_MONST))
panic("no mon type");
tmpmons.id = SP_MONST_PM(OV_i(id));
tmpmons.class = SP_MONST_CLASS(OV_i(id));
tmpmons.coord = OV_i(mcoord);
tmpmons.has_invent = OV_i(has_inv);
create_monster(&tmpmons, coder->croom);
Free(tmpmons.name.str);
Free(tmpmons.appear_as.str);
opvar_free(id);
opvar_free(mcoord);
opvar_free(has_inv);
opvar_free(varparam);
}
spo_object
void
spo_object(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_object";
int nparams = 0;
long quancnt;
struct opvar *varparam;
struct opvar *id, *containment;
object tmpobj;
tmpobj.spe = -127;
tmpobj.curse_state = -1;
tmpobj.corpsenm = NON_PM;
tmpobj.name.str = (char *) 0;
tmpobj.quan = -1;
tmpobj.buried = 0;
tmpobj.lit = 0;
tmpobj.eroded = 0;
tmpobj.locked = 0;
tmpobj.trapped = -1;
tmpobj.recharged = 0;
tmpobj.invis = 0;
tmpobj.greased = 0;
tmpobj.broken = 0;
tmpobj.coord = SP_COORD_PACK_RANDOM(0);
if (!OV_pop_i(containment))
return;
if (!OV_pop_i(varparam))
return;
while ((nparams++ < (SP_O_V_END + 1)) && (OV_typ(varparam) == SPOVAR_INT)
&& (OV_i(varparam) >= 0) && (OV_i(varparam) < SP_O_V_END)) {
struct opvar *parm;
OV_pop(parm);
switch (OV_i(varparam)) {
case SP_O_V_NAME:
if ((OV_typ(parm) == SPOVAR_STRING) && !tmpobj.name.str)
tmpobj.name.str = dupstr(OV_s(parm));
break;
case SP_O_V_CORPSENM:
if (OV_typ(parm) == SPOVAR_MONST) {
char monclass = SP_MONST_CLASS(OV_i(parm));
int monid = SP_MONST_PM(OV_i(parm));
if (monid >= LOW_PM && monid < NUMMONS) {
tmpobj.corpsenm = monid;
break; /* we're done! */
} else {
struct permonst *pm = (struct permonst *) 0;
if (def_char_to_monclass(monclass) != MAXMCLASSES) {
pm = mkclass(def_char_to_monclass(monclass), G_NOGEN);
} else {
pm = rndmonst();
}
if (pm)
tmpobj.corpsenm = monsndx(pm);
}
}
break;
case SP_O_V_CURSE:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.curse_state = OV_i(parm);
break;
case SP_O_V_SPE:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.spe = OV_i(parm);
break;
case SP_O_V_QUAN:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.quan = OV_i(parm);
break;
case SP_O_V_BURIED:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.buried = OV_i(parm);
break;
case SP_O_V_LIT:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.lit = OV_i(parm);
break;
case SP_O_V_ERODED:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.eroded = OV_i(parm);
break;
case SP_O_V_LOCKED:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.locked = OV_i(parm);
break;
case SP_O_V_TRAPPED:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.trapped = OV_i(parm);
break;
case SP_O_V_RECHARGED:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.recharged = OV_i(parm);
break;
case SP_O_V_INVIS:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.invis = OV_i(parm);
break;
case SP_O_V_GREASED:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.greased = OV_i(parm);
break;
case SP_O_V_BROKEN:
if (OV_typ(parm) == SPOVAR_INT)
tmpobj.broken = OV_i(parm);
break;
case SP_O_V_COORD:
if (OV_typ(parm) != SPOVAR_COORD)
panic("no coord for obj?");
tmpobj.coord = OV_i(parm);
break;
case SP_O_V_END:
nparams = SP_O_V_END + 1;
break;
default:
impossible("OBJECT with unknown variable param type!");
break;
}
opvar_free(parm);
if (OV_i(varparam) != SP_O_V_END) {
opvar_free(varparam);
OV_pop(varparam);
}
}
if (!OV_pop_typ(id, SPOVAR_OBJ))
panic("no obj type");
tmpobj.id = SP_OBJ_TYP(OV_i(id));
tmpobj.class = SP_OBJ_CLASS(OV_i(id));
tmpobj.containment = OV_i(containment);
quancnt = (tmpobj.id > STRANGE_OBJECT) ? tmpobj.quan : 0;
do {
create_object(&tmpobj, coder->croom);
quancnt--;
} while ((quancnt > 0) && ((tmpobj.id > STRANGE_OBJECT)
&& !objects[tmpobj.id].oc_merge));
Free(tmpobj.name.str);
opvar_free(varparam);
opvar_free(id);
opvar_free(containment);
}
spo_level_flags
void
spo_level_flags(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_level_flags";
struct opvar *flagdata;
long lflags;
if (!OV_pop_i(flagdata))
return;
lflags = OV_i(flagdata);
if (lflags & NOTELEPORT)
level.flags.noteleport = 1;
if (lflags & HARDFLOOR)
level.flags.hardfloor = 1;
if (lflags & NOMMAP)
level.flags.nommap = 1;
if (lflags & SHORTSIGHTED)
level.flags.shortsighted = 1;
if (lflags & ARBOREAL)
level.flags.arboreal = 1;
if (lflags & MAZELEVEL)
level.flags.is_maze_lev = 1;
if (lflags & PREMAPPED)
coder->premapped = TRUE;
if (lflags & SHROUD)
level.flags.hero_memory = 0;
if (lflags & GRAVEYARD)
level.flags.graveyard = 1;
if (lflags & ICEDPOOLS)
icedpools = TRUE;
if (lflags & SOLIDIFY)
coder->solidify = TRUE;
if (lflags & CORRMAZE)
level.flags.corrmaze = TRUE;
if (lflags & CHECK_INACCESSIBLES)
coder->check_inaccessibles = TRUE;
opvar_free(flagdata);
}
spo_initlevel
void
spo_initlevel(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_initlevel";
lev_init init_lev;
struct opvar *init_style, *fg, *bg, *smoothed, *joined, *lit, *walled,
*filling;
if (!OV_pop_i(fg) || !OV_pop_i(bg) || !OV_pop_i(smoothed)
|| !OV_pop_i(joined) || !OV_pop_i(lit) || !OV_pop_i(walled)
|| !OV_pop_i(filling) || !OV_pop_i(init_style))
return;
splev_init_present = TRUE;
init_lev.init_style = OV_i(init_style);
init_lev.fg = OV_i(fg);
init_lev.bg = OV_i(bg);
init_lev.smoothed = OV_i(smoothed);
init_lev.joined = OV_i(joined);
init_lev.lit = OV_i(lit);
init_lev.walled = OV_i(walled);
init_lev.filling = OV_i(filling);
coder->lvl_is_joined = OV_i(joined);
splev_initlev(&init_lev);
opvar_free(init_style);
opvar_free(fg);
opvar_free(bg);
opvar_free(smoothed);
opvar_free(joined);
opvar_free(lit);
opvar_free(walled);
opvar_free(filling);
}
spo_engraving
void
spo_engraving(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_engraving";
struct opvar *etyp, *txt, *ecoord;
xchar x, y;
if (!OV_pop_i(etyp) || !OV_pop_s(txt) || !OV_pop_c(ecoord))
return;
get_location_coord(&x, &y, DRY, coder->croom, OV_i(ecoord));
make_engr_at(x, y, OV_s(txt), 0L, OV_i(etyp));
opvar_free(etyp);
opvar_free(txt);
opvar_free(ecoord);
}
spo_mineralize
void
spo_mineralize(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_mineralize";
struct opvar *kelp_pool, *kelp_moat, *gold_prob, *gem_prob;
if (!OV_pop_i(gem_prob) || !OV_pop_i(gold_prob) || !OV_pop_i(kelp_moat)
|| !OV_pop_i(kelp_pool))
return;
mineralize(OV_i(kelp_pool), OV_i(kelp_moat), OV_i(gold_prob),
OV_i(gem_prob), TRUE);
opvar_free(gem_prob);
opvar_free(gold_prob);
opvar_free(kelp_moat);
opvar_free(kelp_pool);
}
spo_room
void
spo_room(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_room";
if (coder->n_subroom > MAX_NESTED_ROOMS) {
panic("Too deeply nested rooms?!");
} else {
struct opvar *rflags, *h, *w, *yalign, *xalign, *y, *x, *rlit,
*chance, *rtype;
room tmproom;
struct mkroom *tmpcr;
if (!OV_pop_i(h) || !OV_pop_i(w) || !OV_pop_i(y) || !OV_pop_i(x)
|| !OV_pop_i(yalign) || !OV_pop_i(xalign) || !OV_pop_i(rflags)
|| !OV_pop_i(rlit) || !OV_pop_i(chance) || !OV_pop_i(rtype))
return;
tmproom.x = OV_i(x);
tmproom.y = OV_i(y);
tmproom.w = OV_i(w);
tmproom.h = OV_i(h);
tmproom.xalign = OV_i(xalign);
tmproom.yalign = OV_i(yalign);
tmproom.rtype = OV_i(rtype);
tmproom.chance = OV_i(chance);
tmproom.rlit = OV_i(rlit);
tmproom.filled = (OV_i(rflags) & (1 << 0));
/*tmproom.irregular = (OV_i(rflags) & (1 << 1));*/
tmproom.joined = !(OV_i(rflags) & (1 << 2));
opvar_free(x);
opvar_free(y);
opvar_free(w);
opvar_free(h);
opvar_free(xalign);
opvar_free(yalign);
opvar_free(rtype);
opvar_free(chance);
opvar_free(rlit);
opvar_free(rflags);
if (!coder->failed_room[coder->n_subroom - 1]) {
tmpcr = build_room(&tmproom, coder->croom);
if (tmpcr) {
coder->tmproomlist[coder->n_subroom] = tmpcr;
coder->failed_room[coder->n_subroom] = FALSE;
coder->n_subroom++;
return;
}
} /* failed to create parent room, so fail this too */
}
coder->tmproomlist[coder->n_subroom] = (struct mkroom *) 0;
coder->failed_room[coder->n_subroom] = TRUE;
coder->n_subroom++;
}
spo_endroom
void
spo_endroom(coder)
struct sp_coder *coder;
{
if (coder->n_subroom > 1) {
coder->n_subroom--;
coder->tmproomlist[coder->n_subroom] = NULL;
coder->failed_room[coder->n_subroom] = TRUE;
} else {
/* no subroom, get out of top-level room */
/* Need to ensure xstart/ystart/xsize/ysize have something sensible,
in case there's some stuff to be created outside the outermost
room,
and there's no MAP.
*/
if (xsize <= 1 && ysize <= 1) {
xstart = 1;
ystart = 0;
xsize = COLNO - 1;
ysize = ROWNO;
}
}
}
spo_stair
void
spo_stair(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_stair";
xchar x, y;
struct opvar *up, *scoord;
struct trap *badtrap;
if (!OV_pop_i(up) || !OV_pop_c(scoord))
return;
get_location_coord(&x, &y, DRY, coder->croom, OV_i(scoord));
if ((badtrap = t_at(x, y)) != 0)
deltrap(badtrap);
mkstairs(x, y, (char) OV_i(up), coder->croom);
SpLev_Map[x][y] = 1;
opvar_free(scoord);
opvar_free(up);
}
spo_ladder
void
spo_ladder(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_ladder";
xchar x, y;
struct opvar *up, *lcoord;
if (!OV_pop_i(up) || !OV_pop_c(lcoord))
return;
get_location_coord(&x, &y, DRY, coder->croom, OV_i(lcoord));
levl[x][y].typ = LADDER;
SpLev_Map[x][y] = 1;
if (OV_i(up)) {
xupladder = x;
yupladder = y;
levl[x][y].ladder = LA_UP;
} else {
xdnladder = x;
ydnladder = y;
levl[x][y].ladder = LA_DOWN;
}
opvar_free(lcoord);
opvar_free(up);
}
spo_grave
void
spo_grave(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_grave";
struct opvar *gcoord, *typ, *txt;
schar x, y;
if (!OV_pop_i(typ) || !OV_pop_s(txt) || !OV_pop_c(gcoord))
return;
get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord));
if (isok(x, y) && !t_at(x, y)) {
levl[x][y].typ = GRAVE;
switch (OV_i(typ)) {
case 2:
make_grave(x, y, OV_s(txt));
break;
case 1:
make_grave(x, y, NULL);
break;
default:
del_engr_at(x, y);
break;
}
}
opvar_free(gcoord);
opvar_free(typ);
opvar_free(txt);
}
spo_altar
void
spo_altar(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_altar";
struct opvar *al, *shrine, *acoord;
altar tmpaltar;
if (!OV_pop_i(al) || !OV_pop_i(shrine) || !OV_pop_c(acoord))
return;
tmpaltar.coord = OV_i(acoord);
tmpaltar.align = OV_i(al);
tmpaltar.shrine = OV_i(shrine);
create_altar(&tmpaltar, coder->croom);
opvar_free(acoord);
opvar_free(shrine);
opvar_free(al);
}
spo_trap
void
spo_trap(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_trap";
struct opvar *type;
struct opvar *tcoord;
spltrap tmptrap;
if (!OV_pop_i(type) || !OV_pop_c(tcoord))
return;
tmptrap.coord = OV_i(tcoord);
tmptrap.type = OV_i(type);
create_trap(&tmptrap, coder->croom);
opvar_free(tcoord);
opvar_free(type);
}
spo_gold
void
spo_gold(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_gold";
struct opvar *gcoord, *amt;
schar x, y;
long amount;
if (!OV_pop_c(gcoord) || !OV_pop_i(amt))
return;
amount = OV_i(amt);
get_location_coord(&x, &y, DRY, coder->croom, OV_i(gcoord));
if (amount == -1)
amount = rnd(200);
mkgold(amount, x, y);
opvar_free(gcoord);
opvar_free(amt);
}
spo_corridor
void
spo_corridor(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_corridor";
struct opvar *deswall, *desdoor, *desroom, *srcwall, *srcdoor, *srcroom;
corridor tc;
if (!OV_pop_i(deswall) || !OV_pop_i(desdoor) || !OV_pop_i(desroom)
|| !OV_pop_i(srcwall) || !OV_pop_i(srcdoor) || !OV_pop_i(srcroom))
return;
tc.src.room = OV_i(srcroom);
tc.src.door = OV_i(srcdoor);
tc.src.wall = OV_i(srcwall);
tc.dest.room = OV_i(desroom);
tc.dest.door = OV_i(desdoor);
tc.dest.wall = OV_i(deswall);
create_corridor(&tc);
opvar_free(deswall);
opvar_free(desdoor);
opvar_free(desroom);
opvar_free(srcwall);
opvar_free(srcdoor);
opvar_free(srcroom);
}
selection_opvar
struct opvar *
selection_opvar(nbuf)
char *nbuf;
{
struct opvar *ov;
char buf[(COLNO * ROWNO) + 1];
if (!nbuf) {
(void) memset(buf, 1, sizeof(buf));
buf[(COLNO * ROWNO)] = '\0';
ov = opvar_new_str(buf);
} else {
ov = opvar_new_str(nbuf);
}
ov->spovartyp = SPOVAR_SEL;
return ov;
}
selection_getpoint
xchar
selection_getpoint(x, y, ov)
int x, y;
struct opvar *ov;
{
if (!ov || ov->spovartyp != SPOVAR_SEL)
return 0;
if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
return 0;
return (ov->vardata.str[COLNO * y + x] - 1);
}
selection_setpoint
void
selection_setpoint(x, y, ov, c)
int x, y;
struct opvar *ov;
xchar c;
{
if (!ov || ov->spovartyp != SPOVAR_SEL)
return;
if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
return;
ov->vardata.str[COLNO * y + x] = (char) (c + 1);
}
selection_not
struct opvar *
selection_not(s)
struct opvar *s;
{
struct opvar *ov;
int x, y;
ov = selection_opvar((char *) 0);
if (!ov)
return NULL;
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (!selection_getpoint(x, y, s))
selection_setpoint(x, y, ov, 1);
return ov;
}
selection_logical_oper
struct opvar *
selection_logical_oper(s1, s2, oper)
struct opvar *s1, *s2;
char oper;
{
struct opvar *ov;
int x, y;
ov = selection_opvar((char *) 0);
if (!ov)
return NULL;
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++) {
switch (oper) {
default:
case '|':
if (selection_getpoint(x, y, s1)
|| selection_getpoint(x, y, s2))
selection_setpoint(x, y, ov, 1);
break;
case '&':
if (selection_getpoint(x, y, s1)
&& selection_getpoint(x, y, s2))
selection_setpoint(x, y, ov, 1);
break;
}
}
return ov;
}
selection_filter_mapchar
struct opvar *
selection_filter_mapchar(ov, mc)
struct opvar *ov;
struct opvar *mc;
{
int x, y;
schar mapc;
xchar lit;
struct opvar *ret = selection_opvar((char *) 0);
if (!ov || !mc || !ret)
return NULL;
mapc = SP_MAPCHAR_TYP(OV_i(mc));
lit = SP_MAPCHAR_LIT(OV_i(mc));
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (selection_getpoint(x, y, ov) && (levl[x][y].typ == mapc)) {
switch (lit) {
default:
case -2:
selection_setpoint(x, y, ret, 1);
break;
case -1:
selection_setpoint(x, y, ret, rn2(2));
break;
case 0:
case 1:
if (levl[x][y].lit == lit)
selection_setpoint(x, y, ret, 1);
break;
}
}
return ret;
}
selection_filter_percent
void
selection_filter_percent(ov, percent)
struct opvar *ov;
int percent;
{
int x, y;
if (!ov)
return;
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (selection_getpoint(x, y, ov) && (rn2(100) >= percent))
selection_setpoint(x, y, ov, 0);
}
selection_rndcoord
STATIC_OVL int
selection_rndcoord(ov, x, y, removeit)
struct opvar *ov;
schar *x, *y;
boolean removeit;
{
int idx = 0;
int c;
int dx, dy;
for (dx = 0; dx < COLNO; dx++)
for (dy = 0; dy < ROWNO; dy++)
if (isok(dx, dy) && selection_getpoint(dx, dy, ov))
idx++;
if (idx) {
c = rn2(idx);
for (dx = 0; dx < COLNO; dx++)
for (dy = 0; dy < ROWNO; dy++)
if (isok(dx, dy) && selection_getpoint(dx, dy, ov)) {
if (!c) {
*x = dx;
*y = dy;
if (removeit) selection_setpoint(dx, dy, ov, 0);
return 1;
}
c--;
}
}
*x = *y = -1;
return 0;
}
selection_do_grow
void
selection_do_grow(ov, dir)
struct opvar *ov;
int dir;
{
int x, y, c;
char tmp[COLNO][ROWNO];
if (ov->spovartyp != SPOVAR_SEL)
return;
if (!ov)
return;
(void) memset(tmp, 0, sizeof(tmp));
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++) {
c = 0;
if ((dir & W_WEST) && (x > 0)
&& (selection_getpoint(x - 1, y, ov)))
c++;
if ((dir & (W_WEST | W_NORTH)) && (x > 0) && (y > 0)
&& (selection_getpoint(x - 1, y - 1, ov)))
c++;
if ((dir & W_NORTH) && (y > 0)
&& (selection_getpoint(x, y - 1, ov)))
c++;
if ((dir & (W_NORTH | W_EAST)) && (y > 0) && (x < COLNO - 1)
&& (selection_getpoint(x + 1, y - 1, ov)))
c++;
if ((dir & W_EAST) && (x < COLNO - 1)
&& (selection_getpoint(x + 1, y, ov)))
c++;
if ((dir & (W_EAST | W_SOUTH)) && (x < COLNO - 1)
&& (y < ROWNO - 1) && (selection_getpoint(x + 1, y + 1, ov)))
c++;
if ((dir & W_SOUTH) && (y < ROWNO - 1)
&& (selection_getpoint(x, y + 1, ov)))
c++;
if ((dir & (W_SOUTH | W_WEST)) && (y < ROWNO - 1) && (x > 0)
&& (selection_getpoint(x - 1, y + 1, ov)))
c++;
if (c)
tmp[x][y] = 1;
}
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (tmp[x][y])
selection_setpoint(x, y, ov, 1);
}
STATIC_VAR int FDECL((*selection_flood_check_func), (int, int));
STATIC_VAR schar floodfillchk_match_under_typ;
set_selection_floodfillchk
void
set_selection_floodfillchk(f)
int FDECL((*f), (int, int));
{
selection_flood_check_func = f;
}
floodfillchk_match_under
STATIC_OVL int
floodfillchk_match_under(x,y)
int x,y;
{
return (floodfillchk_match_under_typ == levl[x][y].typ);
}
floodfillchk_match_accessible
STATIC_OVL int
floodfillchk_match_accessible(x, y)
int x, y;
{
return (ACCESSIBLE(levl[x][y].typ)
|| levl[x][y].typ == SDOOR
|| levl[x][y].typ == SCORR);
}
selection_floodfill
void
selection_floodfill(ov, x, y, diagonals)
struct opvar *ov;
int x, y;
boolean diagonals;
{
static const char nhFunc[] = "selection_floodfill";
struct opvar *tmp = selection_opvar((char *) 0);
#define SEL_FLOOD_STACK (COLNO * ROWNO)
#define SEL_FLOOD(nx, ny) \
do { \
if (idx < SEL_FLOOD_STACK) { \
dx[idx] = (nx); \
dy[idx] = (ny); \
idx++; \
} else \
panic(floodfill_stack_overrun); \
} while (0)
#define SEL_FLOOD_CHKDIR(mx,my,sel) \
if (isok((mx), (my)) \
&& (*selection_flood_check_func)((mx), (my)) \
&& !selection_getpoint((mx), (my), (sel))) \
SEL_FLOOD((mx), (my))
static const char floodfill_stack_overrun[] = "floodfill stack overrun";
int idx = 0;
xchar dx[SEL_FLOOD_STACK];
xchar dy[SEL_FLOOD_STACK];
if (selection_flood_check_func == NULL) {
opvar_free(tmp);
return;
}
SEL_FLOOD(x, y);
do {
idx--;
x = dx[idx];
y = dy[idx];
if (isok(x, y)) {
selection_setpoint(x, y, ov, 1);
selection_setpoint(x, y, tmp, 1);
}
SEL_FLOOD_CHKDIR((x + 1), y, tmp);
SEL_FLOOD_CHKDIR((x - 1), y, tmp);
SEL_FLOOD_CHKDIR(x, (y + 1), tmp);
SEL_FLOOD_CHKDIR(x, (y - 1), tmp);
if (diagonals) {
SEL_FLOOD_CHKDIR((x + 1), (y + 1), tmp);
SEL_FLOOD_CHKDIR((x - 1), (y - 1), tmp);
SEL_FLOOD_CHKDIR((x - 1), (y + 1), tmp);
SEL_FLOOD_CHKDIR((x + 1), (y - 1), tmp);
}
} while (idx > 0);
#undef SEL_FLOOD
#undef SEL_FLOOD_STACK
#undef SEL_FLOOD_CHKDIR
opvar_free(tmp);
}
selection_do_ellipse
/* McIlroy's Ellipse Algorithm */
void
selection_do_ellipse(ov, xc, yc, a, b, filled)
struct opvar *ov;
int xc, yc, a, b, filled;
{ /* e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2 */
int x = 0, y = b;
long a2 = (long) a * a, b2 = (long) b * b;
long crit1 = -(a2 / 4 + a % 2 + b2);
long crit2 = -(b2 / 4 + b % 2 + a2);
long crit3 = -(b2 / 4 + b % 2);
long t = -a2 * y; /* e(x+1/2,y-1/2) - (a^2+b^2)/4 */
long dxt = 2 * b2 * x, dyt = -2 * a2 * y;
long d2xt = 2 * b2, d2yt = 2 * a2;
long width = 1;
long i;
if (!ov)
return;
filled = !filled;
if (!filled) {
while (y >= 0 && x <= a) {
selection_setpoint(xc + x, yc + y, ov, 1);
if (x != 0 || y != 0)
selection_setpoint(xc - x, yc - y, ov, 1);
if (x != 0 && y != 0) {
selection_setpoint(xc + x, yc - y, ov, 1);
selection_setpoint(xc - x, yc + y, ov, 1);
}
if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
|| t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
x++;
dxt += d2xt;
t += dxt;
} else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
y--;
dyt += d2yt;
t += dyt;
} else {
x++;
dxt += d2xt;
t += dxt;
y--;
dyt += d2yt;
t += dyt;
}
}
} else {
while (y >= 0 && x <= a) {
if (t + b2 * x <= crit1 /* e(x+1,y-1/2) <= 0 */
|| t + a2 * y <= crit3) { /* e(x+1/2,y) <= 0 */
x++;
dxt += d2xt;
t += dxt;
width += 2;
} else if (t - a2 * y > crit2) { /* e(x+1/2,y-1) > 0 */
for (i = 0; i < width; i++)
selection_setpoint(xc - x + i, yc - y, ov, 1);
if (y != 0)
for (i = 0; i < width; i++)
selection_setpoint(xc - x + i, yc + y, ov, 1);
y--;
dyt += d2yt;
t += dyt;
} else {
for (i = 0; i < width; i++)
selection_setpoint(xc - x + i, yc - y, ov, 1);
if (y != 0)
for (i = 0; i < width; i++)
selection_setpoint(xc - x + i, yc + y, ov, 1);
x++;
dxt += d2xt;
t += dxt;
y--;
dyt += d2yt;
t += dyt;
width += 2;
}
}
}
}
line_dist_coord
/* distance from line segment (x1,y1, x2,y2) to point (x3,y3) */
long
line_dist_coord(x1, y1, x2, y2, x3, y3)
long x1, y1, x2, y2, x3, y3;
{
long px = x2 - x1;
long py = y2 - y1;
long s = px * px + py * py;
long x, y, dx, dy, dist = 0;
float lu = 0;
if (x1 == x2 && y1 == y2)
return isqrt(dist2(x1, y1, x3, y3));
lu = ((x3 - x1) * px + (y3 - y1) * py) / (float) s;
if (lu > 1)
lu = 1;
else if (lu < 0)
lu = 0;
x = x1 + lu * px;
y = y1 + lu * py;
dx = x - x3;
dy = y - y3;
dist = isqrt(dx * dx + dy * dy);
return dist;
}
selection_do_gradient
void
selection_do_gradient(ov, x, y, x2, y2, gtyp, mind, maxd, limit)
struct opvar *ov;
long x, y, x2, y2, gtyp, mind, maxd, limit;
{
long dx, dy, dofs;
if (mind > maxd) {
long tmp = mind;
mind = maxd;
maxd = tmp;
}
dofs = maxd - mind;
if (dofs < 1)
dofs = 1;
switch (gtyp) {
default:
case SEL_GRADIENT_RADIAL: {
for (dx = 0; dx < COLNO; dx++)
for (dy = 0; dy < ROWNO; dy++) {
long d0 = line_dist_coord(x, y, x2, y2, dx, dy);
if (d0 >= mind && (!limit || d0 <= maxd)) {
if (d0 - mind > rn2(dofs))
selection_setpoint(dx, dy, ov, 1);
}
}
break;
}
case SEL_GRADIENT_SQUARE: {
for (dx = 0; dx < COLNO; dx++)
for (dy = 0; dy < ROWNO; dy++) {
long d1 = line_dist_coord(x, y, x2, y2, x, dy);
long d2 = line_dist_coord(x, y, x2, y2, dx, y);
long d3 = line_dist_coord(x, y, x2, y2, x2, dy);
long d4 = line_dist_coord(x, y, x2, y2, dx, y2);
long d5 = line_dist_coord(x, y, x2, y2, dx, dy);
long d0 = min(d5, min(max(d1, d2), max(d3, d4)));
if (d0 >= mind && (!limit || d0 <= maxd)) {
if (d0 - mind > rn2(dofs))
selection_setpoint(dx, dy, ov, 1);
}
}
break;
} /*case*/
} /*switch*/
}
selection_do_line
/* bresenham line algo */
void
selection_do_line(x1, y1, x2, y2, ov)
schar x1, y1, x2, y2;
struct opvar *ov;
{
int d0, dx, dy, ai, bi, xi, yi;
if (x1 < x2) {
xi = 1;
dx = x2 - x1;
} else {
xi = -1;
dx = x1 - x2;
}
if (y1 < y2) {
yi = 1;
dy = y2 - y1;
} else {
yi = -1;
dy = y1 - y2;
}
selection_setpoint(x1, y1, ov, 1);
if (dx > dy) {
ai = (dy - dx) * 2;
bi = dy * 2;
d0 = bi - dx;
do {
if (d0 >= 0) {
y1 += yi;
d0 += ai;
} else
d0 += bi;
x1 += xi;
selection_setpoint(x1, y1, ov, 1);
} while (x1 != x2);
} else {
ai = (dx - dy) * 2;
bi = dx * 2;
d0 = bi - dy;
do {
if (d0 >= 0) {
x1 += xi;
d0 += ai;
} else
d0 += bi;
y1 += yi;
selection_setpoint(x1, y1, ov, 1);
} while (y1 != y2);
}
}
selection_do_randline
void
selection_do_randline(x1, y1, x2, y2, rough, rec, ov)
schar x1, y1, x2, y2, rough, rec;
struct opvar *ov;
{
int mx, my;
int dx, dy;
if (rec < 1) {
return;
}
if ((x2 == x1) && (y2 == y1)) {
selection_setpoint(x1, y1, ov, 1);
return;
}
if (rough > max(abs(x2 - x1), abs(y2 - y1)))
rough = max(abs(x2 - x1), abs(y2 - y1));
if (rough < 2) {
mx = ((x1 + x2) / 2);
my = ((y1 + y2) / 2);
} else {
do {
dx = rn2(rough) - (rough / 2);
dy = rn2(rough) - (rough / 2);
mx = ((x1 + x2) / 2) + dx;
my = ((y1 + y2) / 2) + dy;
} while ((mx > COLNO - 1 || mx < 0 || my < 0 || my > ROWNO - 1));
}
selection_setpoint(mx, my, ov, 1);
rough = (rough * 2) / 3;
rec--;
selection_do_randline(x1, y1, mx, my, rough, rec, ov);
selection_do_randline(mx, my, x2, y2, rough, rec, ov);
}
selection_iterate
void
selection_iterate(ov, func, arg)
struct opvar *ov;
select_iter_func func;
genericptr_t arg;
{
int x, y;
/* yes, this is very naive, but it's not _that_ expensive. */
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (selection_getpoint(x, y, ov))
(*func)(x, y, arg);
}
sel_set_ter
void
sel_set_ter(x, y, arg)
int x, y;
genericptr_t arg;
{
terrain terr;
terr = *(terrain *) arg;
SET_TYPLIT(x, y, terr.ter, terr.tlit);
/* handle doors and secret doors */
if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
if (levl[x][y].typ == SDOOR)
levl[x][y].doormask = D_CLOSED;
if (x && (IS_WALL(levl[x - 1][y].typ) || levl[x - 1][y].horizontal))
levl[x][y].horizontal = 1;
}
}
sel_set_feature
void
sel_set_feature(x, y, arg)
int x, y;
genericptr_t arg;
{
if (IS_FURNITURE(levl[x][y].typ))
return;
levl[x][y].typ = (*(int *) arg);
}
sel_set_door
void
sel_set_door(dx, dy, arg)
int dx, dy;
genericptr_t arg;
{
xchar typ = *(xchar *) arg;
xchar x = dx, y = dy;
if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR)
levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR;
if (typ & D_SECRET) {
typ &= ~D_SECRET;
if (typ < D_CLOSED)
typ = D_CLOSED;
}
set_door_orientation(x, y); /* set/clear levl[x][y].horizontal */
levl[x][y].doormask = typ;
SpLev_Map[x][y] = 1;
}
spo_door
void
spo_door(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_door";
struct opvar *msk, *sel;
xchar typ;
if (!OV_pop_i(msk) || !OV_pop_typ(sel, SPOVAR_SEL))
return;
typ = OV_i(msk) == -1 ? rnddoor() : (xchar) OV_i(msk);
selection_iterate(sel, sel_set_door, (genericptr_t) &typ);
opvar_free(sel);
opvar_free(msk);
}
spo_feature
void
spo_feature(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_feature";
struct opvar *sel;
int typ;
if (!OV_pop_typ(sel, SPOVAR_SEL))
return;
switch (coder->opcode) {
default:
impossible("spo_feature called with wrong opcode %i.", coder->opcode);
break;
case SPO_FOUNTAIN:
typ = FOUNTAIN;
break;
case SPO_SINK:
typ = SINK;
break;
case SPO_POOL:
typ = POOL;
break;
}
selection_iterate(sel, sel_set_feature, (genericptr_t) &typ);
opvar_free(sel);
}
spo_terrain
void
spo_terrain(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_terrain";
terrain tmpterrain;
struct opvar *ter, *sel;
if (!OV_pop_typ(ter, SPOVAR_MAPCHAR) || !OV_pop_typ(sel, SPOVAR_SEL))
return;
tmpterrain.ter = SP_MAPCHAR_TYP(OV_i(ter));
tmpterrain.tlit = SP_MAPCHAR_LIT(OV_i(ter));
selection_iterate(sel, sel_set_ter, (genericptr_t) &tmpterrain);
opvar_free(ter);
opvar_free(sel);
}
spo_replace_terrain
void
spo_replace_terrain(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_replace_terrain";
replaceterrain rt;
struct opvar *reg, *from_ter, *to_ter, *chance;
if (!OV_pop_i(chance) || !OV_pop_typ(to_ter, SPOVAR_MAPCHAR)
|| !OV_pop_typ(from_ter, SPOVAR_MAPCHAR) || !OV_pop_r(reg))
return;
rt.chance = OV_i(chance);
rt.tolit = SP_MAPCHAR_LIT(OV_i(to_ter));
rt.toter = SP_MAPCHAR_TYP(OV_i(to_ter));
rt.fromter = SP_MAPCHAR_TYP(OV_i(from_ter));
/* TODO: use SP_MAPCHAR_LIT(OV_i(from_ter)) too */
rt.x1 = SP_REGION_X1(OV_i(reg));
rt.y1 = SP_REGION_Y1(OV_i(reg));
rt.x2 = SP_REGION_X2(OV_i(reg));
rt.y2 = SP_REGION_Y2(OV_i(reg));
replace_terrain(&rt, coder->croom);
opvar_free(reg);
opvar_free(from_ter);
opvar_free(to_ter);
opvar_free(chance);
}
generate_way_out_method
STATIC_OVL boolean
generate_way_out_method(nx,ny, ov)
int nx,ny;
struct opvar *ov;
{
static const char nhFunc[] = "generate_way_out_method";
const int escapeitems[] = { PICK_AXE,
DWARVISH_MATTOCK,
WAN_DIGGING,
WAN_TELEPORTATION,
SCR_TELEPORTATION,
RIN_TELEPORTATION };
struct opvar *ov2 = selection_opvar((char *) 0), *ov3;
schar x, y;
boolean res = TRUE;
selection_floodfill(ov2, nx, ny, TRUE);
ov3 = opvar_clone(ov2);
/* try to make a secret door */
while (selection_rndcoord(ov3, &x, &y, TRUE)) {
if (isok(x+1, y) && !selection_getpoint(x+1, y, ov)
&& IS_WALL(levl[x+1][y].typ)
&& isok(x+2, y) && selection_getpoint(x+2, y, ov)
&& ACCESSIBLE(levl[x+2][y].typ)) {
levl[x+1][y].typ = SDOOR;
goto gotitdone;
}
if (isok(x-1, y) && !selection_getpoint(x-1, y, ov)
&& IS_WALL(levl[x-1][y].typ)
&& isok(x-2, y) && selection_getpoint(x-2, y, ov)
&& ACCESSIBLE(levl[x-2][y].typ)) {
levl[x-1][y].typ = SDOOR;
goto gotitdone;
}
if (isok(x, y+1) && !selection_getpoint(x, y+1, ov)
&& IS_WALL(levl[x][y+1].typ)
&& isok(x, y+2) && selection_getpoint(x, y+2, ov)
&& ACCESSIBLE(levl[x][y+2].typ)) {
levl[x][y+1].typ = SDOOR;
goto gotitdone;
}
if (isok(x, y-1) && !selection_getpoint(x, y-1, ov)
&& IS_WALL(levl[x][y-1].typ)
&& isok(x, y-2) && selection_getpoint(x, y-2, ov)
&& ACCESSIBLE(levl[x][y-2].typ)) {
levl[x][y-1].typ = SDOOR;
goto gotitdone;
}
}
/* try to make a hole or a trapdoor */
if (Can_fall_thru(&u.uz)) {
opvar_free(ov3);
ov3 = opvar_clone(ov2);
while (selection_rndcoord(ov3, &x, &y, TRUE)) {
if (maketrap(x,y, rn2(2) ? HOLE : TRAPDOOR))
goto gotitdone;
}
}
/* generate one of the escape items */
if (selection_rndcoord(ov2, &x, &y, FALSE)) {
mksobj_at(escapeitems[rn2(SIZE(escapeitems))], x, y, TRUE, FALSE);
goto gotitdone;
}
res = FALSE;
gotitdone:
opvar_free(ov2);
opvar_free(ov3);
return res;
}
ensure_way_out
STATIC_OVL void
ensure_way_out()
{
static const char nhFunc[] = "ensure_way_out";
struct opvar *ov = selection_opvar((char *) 0);
struct trap *ttmp = ftrap;
int x,y;
boolean ret = TRUE;
set_selection_floodfillchk(floodfillchk_match_accessible);
if (xupstair && !selection_getpoint(xupstair, yupstair, ov))
selection_floodfill(ov, xupstair, yupstair, TRUE);
if (xdnstair && !selection_getpoint(xdnstair, ydnstair, ov))
selection_floodfill(ov, xdnstair, ydnstair, TRUE);
if (xupladder && !selection_getpoint(xupladder, yupladder, ov))
selection_floodfill(ov, xupladder, yupladder, TRUE);
if (xdnladder && !selection_getpoint(xdnladder, ydnladder, ov))
selection_floodfill(ov, xdnladder, ydnladder, TRUE);
while (ttmp) {
if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE
|| ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR)
&& !selection_getpoint(ttmp->tx, ttmp->ty, ov))
selection_floodfill(ov, ttmp->tx, ttmp->ty, TRUE);
ttmp = ttmp->ntrap;
}
do {
ret = TRUE;
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if (ACCESSIBLE(levl[x][y].typ)
&& !selection_getpoint(x, y, ov)) {
if (generate_way_out_method(x,y, ov))
selection_floodfill(ov, x,y, TRUE);
ret = FALSE;
goto outhere;
}
outhere: ;
} while (!ret);
opvar_free(ov);
}
spo_levregion
void
spo_levregion(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_levregion";
struct opvar *rname, *padding, *rtype, *del_islev, *dy2, *dx2, *dy1, *dx1,
*in_islev, *iy2, *ix2, *iy1, *ix1;
lev_region *tmplregion;
if (!OV_pop_s(rname) || !OV_pop_i(padding) || !OV_pop_i(rtype)
|| !OV_pop_i(del_islev) || !OV_pop_i(dy2) || !OV_pop_i(dx2)
|| !OV_pop_i(dy1) || !OV_pop_i(dx1) || !OV_pop_i(in_islev)
|| !OV_pop_i(iy2) || !OV_pop_i(ix2) || !OV_pop_i(iy1)
|| !OV_pop_i(ix1))
return;
tmplregion = (lev_region *) alloc(sizeof(lev_region));
tmplregion->inarea.x1 = OV_i(ix1);
tmplregion->inarea.y1 = OV_i(iy1);
tmplregion->inarea.x2 = OV_i(ix2);
tmplregion->inarea.y2 = OV_i(iy2);
tmplregion->delarea.x1 = OV_i(dx1);
tmplregion->delarea.y1 = OV_i(dy1);
tmplregion->delarea.x2 = OV_i(dx2);
tmplregion->delarea.y2 = OV_i(dy2);
tmplregion->in_islev = OV_i(in_islev);
tmplregion->del_islev = OV_i(del_islev);
tmplregion->rtype = OV_i(rtype);
tmplregion->padding = OV_i(padding);
tmplregion->rname.str = dupstr(OV_s(rname));
if (!tmplregion->in_islev) {
get_location(&tmplregion->inarea.x1, &tmplregion->inarea.y1, ANY_LOC,
(struct mkroom *) 0);
get_location(&tmplregion->inarea.x2, &tmplregion->inarea.y2, ANY_LOC,
(struct mkroom *) 0);
}
if (!tmplregion->del_islev) {
get_location(&tmplregion->delarea.x1, &tmplregion->delarea.y1,
ANY_LOC, (struct mkroom *) 0);
get_location(&tmplregion->delarea.x2, &tmplregion->delarea.y2,
ANY_LOC, (struct mkroom *) 0);
}
if (num_lregions) {
/* realloc the lregion space to add the new one */
lev_region *newl = (lev_region *) alloc(
sizeof(lev_region) * (unsigned) (1 + num_lregions));
(void) memcpy((genericptr_t) (newl), (genericptr_t) lregions,
sizeof(lev_region) * num_lregions);
Free(lregions);
num_lregions++;
lregions = newl;
} else {
num_lregions = 1;
lregions = (lev_region *) alloc(sizeof(lev_region));
}
(void) memcpy(&lregions[num_lregions - 1], tmplregion,
sizeof(lev_region));
free(tmplregion);
opvar_free(dx1);
opvar_free(dy1);
opvar_free(dx2);
opvar_free(dy2);
opvar_free(ix1);
opvar_free(iy1);
opvar_free(ix2);
opvar_free(iy2);
opvar_free(del_islev);
opvar_free(in_islev);
opvar_free(rname);
opvar_free(rtype);
opvar_free(padding);
}
spo_region
void
spo_region(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_region";
struct opvar *rtype, *rlit, *rflags, *area;
xchar dx1, dy1, dx2, dy2;
register struct mkroom *troom;
boolean prefilled, room_not_needed, irregular, joined;
if (!OV_pop_i(rflags) || !OV_pop_i(rtype) || !OV_pop_i(rlit)
|| !OV_pop_r(area))
return;
prefilled = !(OV_i(rflags) & (1 << 0));
irregular = (OV_i(rflags) & (1 << 1));
joined = !(OV_i(rflags) & (1 << 2));
if (OV_i(rtype) > MAXRTYPE) {
OV_i(rtype) -= MAXRTYPE + 1;
prefilled = TRUE;
} else
prefilled = FALSE;
if (OV_i(rlit) < 0)
OV_i(rlit) =
(rnd(1 + abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
dx1 = SP_REGION_X1(OV_i(area));
dy1 = SP_REGION_Y1(OV_i(area));
dx2 = SP_REGION_X2(OV_i(area));
dy2 = SP_REGION_Y2(OV_i(area));
get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0);
get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0);
/* for an ordinary room, `prefilled' is a flag to force
an actual room to be created (such rooms are used to
control placement of migrating monster arrivals) */
room_not_needed = (OV_i(rtype) == OROOM && !irregular && !prefilled);
if (room_not_needed || nroom >= MAXNROFROOMS) {
region tmpregion;
if (!room_not_needed)
impossible("Too many rooms on new level!");
tmpregion.rlit = OV_i(rlit);
tmpregion.x1 = dx1;
tmpregion.y1 = dy1;
tmpregion.x2 = dx2;
tmpregion.y2 = dy2;
light_region(&tmpregion);
opvar_free(area);
opvar_free(rflags);
opvar_free(rlit);
opvar_free(rtype);
return;
}
troom = &rooms[nroom];
/* mark rooms that must be filled, but do it later */
if (OV_i(rtype) != OROOM)
troom->needfill = (prefilled ? 2 : 1);
troom->needjoining = joined;
if (irregular) {
min_rx = max_rx = dx1;
min_ry = max_ry = dy1;
smeq[nroom] = nroom;
flood_fill_rm(dx1, dy1, nroom + ROOMOFFSET, OV_i(rlit), TRUE);
add_room(min_rx, min_ry, max_rx, max_ry, FALSE, OV_i(rtype), TRUE);
troom->rlit = OV_i(rlit);
troom->irregular = TRUE;
} else {
add_room(dx1, dy1, dx2, dy2, OV_i(rlit), OV_i(rtype), TRUE);
#ifdef SPECIALIZATION
topologize(troom, FALSE); /* set roomno */
#else
topologize(troom); /* set roomno */
#endif
}
if (!room_not_needed) {
if (coder->n_subroom > 1)
impossible("region as subroom");
else {
coder->tmproomlist[coder->n_subroom] = troom;
coder->failed_room[coder->n_subroom] = FALSE;
coder->n_subroom++;
}
}
opvar_free(area);
opvar_free(rflags);
opvar_free(rlit);
opvar_free(rtype);
}
spo_drawbridge
void
spo_drawbridge(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_drawbridge";
xchar x, y;
struct opvar *dir, *db_open, *dcoord;
if (!OV_pop_i(dir) || !OV_pop_i(db_open) || !OV_pop_c(dcoord))
return;
get_location_coord(&x, &y, DRY | WET | HOT, coder->croom, OV_i(dcoord));
if (!create_drawbridge(x, y, OV_i(dir), OV_i(db_open)))
impossible("Cannot create drawbridge.");
SpLev_Map[x][y] = 1;
opvar_free(dcoord);
opvar_free(db_open);
opvar_free(dir);
}
spo_mazewalk
void
spo_mazewalk(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_mazewalk";
xchar x, y;
struct opvar *ftyp, *fstocked, *fdir, *mcoord;
int dir;
if (!OV_pop_i(ftyp) || !OV_pop_i(fstocked) || !OV_pop_i(fdir)
|| !OV_pop_c(mcoord))
return;
dir = OV_i(fdir);
get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(mcoord));
if (!isok(x, y))
return;
if (OV_i(ftyp) < 1) {
OV_i(ftyp) = level.flags.corrmaze ? CORR : ROOM;
}
/* don't use move() - it doesn't use W_NORTH, etc. */
switch (dir) {
case W_NORTH:
--y;
break;
case W_SOUTH:
y++;
break;
case W_EAST:
x++;
break;
case W_WEST:
--x;
break;
default:
impossible("spo_mazewalk: Bad MAZEWALK direction");
}
if (!IS_DOOR(levl[x][y].typ)) {
levl[x][y].typ = OV_i(ftyp);
levl[x][y].flags = 0;
}
/*
* We must be sure that the parity of the coordinates for
* walkfrom() is odd. But we must also take into account
* what direction was chosen.
*/
if (!(x % 2)) {
if (dir == W_EAST)
x++;
else
x--;
/* no need for IS_DOOR check; out of map bounds */
levl[x][y].typ = OV_i(ftyp);
levl[x][y].flags = 0;
}
if (!(y % 2)) {
if (dir == W_SOUTH)
y++;
else
y--;
}
walkfrom(x, y, OV_i(ftyp));
if (OV_i(fstocked))
fill_empty_maze();
opvar_free(mcoord);
opvar_free(fdir);
opvar_free(fstocked);
opvar_free(ftyp);
}
spo_wall_property
void
spo_wall_property(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_wall_property";
struct opvar *r;
xchar dx1, dy1, dx2, dy2;
int wprop = (coder->opcode == SPO_NON_DIGGABLE)
? W_NONDIGGABLE
: W_NONPASSWALL;
if (!OV_pop_r(r))
return;
dx1 = SP_REGION_X1(OV_i(r));
dy1 = SP_REGION_Y1(OV_i(r));
dx2 = SP_REGION_X2(OV_i(r));
dy2 = SP_REGION_Y2(OV_i(r));
get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0);
get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0);
set_wall_property(dx1, dy1, dx2, dy2, wprop);
opvar_free(r);
}
spo_room_door
void
spo_room_door(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_room_door";
struct opvar *wall, *secret, *mask, *pos;
room_door tmpd;
if (!OV_pop_i(wall) || !OV_pop_i(secret) || !OV_pop_i(mask)
|| !OV_pop_i(pos) || !coder->croom)
return;
tmpd.secret = OV_i(secret);
tmpd.mask = OV_i(mask);
tmpd.pos = OV_i(pos);
tmpd.wall = OV_i(wall);
create_door(&tmpd, coder->croom);
opvar_free(wall);
opvar_free(secret);
opvar_free(mask);
opvar_free(pos);
}
/*ARGSUSED*/
sel_set_wallify
void
sel_set_wallify(x, y, arg)
int x, y;
genericptr_t arg UNUSED;
{
wallify_map(x, y, x, y);
}
spo_wallify
void
spo_wallify(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_wallify";
struct opvar *typ, *r;
int dx1, dy1, dx2, dy2;
if (!OV_pop_i(typ))
return;
switch (OV_i(typ)) {
default:
case 0:
if (!OV_pop_r(r))
return;
dx1 = (xchar) SP_REGION_X1(OV_i(r));
dy1 = (xchar) SP_REGION_Y1(OV_i(r));
dx2 = (xchar) SP_REGION_X2(OV_i(r));
dy2 = (xchar) SP_REGION_Y2(OV_i(r));
wallify_map(dx1 < 0 ? (xstart - 1) : dx1,
dy1 < 0 ? (ystart - 1) : dy1,
dx2 < 0 ? (xstart + xsize + 1) : dx2,
dy2 < 0 ? (ystart + ysize + 1) : dy2);
break;
case 1:
if (!OV_pop_typ(r, SPOVAR_SEL))
return;
selection_iterate(r, sel_set_wallify, NULL);
break;
}
opvar_free(r);
opvar_free(typ);
}
spo_map
void
spo_map(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_map";
mazepart tmpmazepart;
struct opvar *mpxs, *mpys, *mpmap, *mpa, *mpkeepr, *mpzalign;
xchar halign, valign;
xchar tmpxstart, tmpystart, tmpxsize, tmpysize;
unpacked_coord upc;
if (!OV_pop_i(mpxs) || !OV_pop_i(mpys) || !OV_pop_s(mpmap)
|| !OV_pop_i(mpkeepr) || !OV_pop_i(mpzalign) || !OV_pop_c(mpa))
return;
tmpmazepart.xsize = OV_i(mpxs);
tmpmazepart.ysize = OV_i(mpys);
tmpmazepart.zaligntyp = OV_i(mpzalign);
upc = get_unpacked_coord(OV_i(mpa), ANY_LOC);
tmpmazepart.halign = upc.x;
tmpmazepart.valign = upc.y;
tmpxsize = xsize;
tmpysize = ysize;
tmpxstart = xstart;
tmpystart = ystart;
halign = tmpmazepart.halign;
valign = tmpmazepart.valign;
xsize = tmpmazepart.xsize;
ysize = tmpmazepart.ysize;
switch (tmpmazepart.zaligntyp) {
default:
case 0:
break;
case 1:
switch ((int) halign) {
case LEFT:
xstart = splev_init_present ? 1 : 3;
break;
case H_LEFT:
xstart = 2 + ((x_maze_max - 2 - xsize) / 4);
break;
case CENTER:
xstart = 2 + ((x_maze_max - 2 - xsize) / 2);
break;
case H_RIGHT:
xstart = 2 + ((x_maze_max - 2 - xsize) * 3 / 4);
break;
case RIGHT:
xstart = x_maze_max - xsize - 1;
break;
}
switch ((int) valign) {
case TOP:
ystart = 3;
break;
case CENTER:
ystart = 2 + ((y_maze_max - 2 - ysize) / 2);
break;
case BOTTOM:
ystart = y_maze_max - ysize - 1;
break;
}
if (!(xstart % 2))
xstart++;
if (!(ystart % 2))
ystart++;
break;
case 2:
if (!coder->croom) {
xstart = 1;
ystart = 0;
xsize = COLNO - 1 - tmpmazepart.xsize;
ysize = ROWNO - tmpmazepart.ysize;
}
get_location_coord(&halign, &valign, ANY_LOC, coder->croom,
OV_i(mpa));
xsize = tmpmazepart.xsize;
ysize = tmpmazepart.ysize;
xstart = halign;
ystart = valign;
break;
}
if (ystart < 0 || ystart + ysize > ROWNO) {
/* try to move the start a bit */
ystart += (ystart > 0) ? -2 : 2;
if (ysize == ROWNO)
ystart = 0;
if (ystart < 0 || ystart + ysize > ROWNO)
panic("reading special level with ysize too large");
}
if (xsize <= 1 && ysize <= 1) {
xstart = 1;
ystart = 0;
xsize = COLNO - 1;
ysize = ROWNO;
} else {
xchar x, y, mptyp;
/* Load the map */
for (y = ystart; y < ystart + ysize; y++)
for (x = xstart; x < xstart + xsize; x++) {
mptyp = (mpmap->vardata.str[(y - ystart) * xsize
+ (x - xstart)] - 1);
if (mptyp >= MAX_TYPE)
continue;
levl[x][y].typ = mptyp;
levl[x][y].lit = FALSE;
/* clear out levl: load_common_data may set them */
levl[x][y].flags = 0;
levl[x][y].horizontal = 0;
levl[x][y].roomno = 0;
levl[x][y].edge = 0;
SpLev_Map[x][y] = 1;
/*
* Set secret doors to closed (why not trapped too?). Set
* the horizontal bit.
*/
if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
if (levl[x][y].typ == SDOOR)
levl[x][y].doormask = D_CLOSED;
/*
* If there is a wall to the left that connects to a
* (secret) door, then it is horizontal. This does
* not allow (secret) doors to be corners of rooms.
*/
if (x != xstart && (IS_WALL(levl[x - 1][y].typ)
|| levl[x - 1][y].horizontal))
levl[x][y].horizontal = 1;
} else if (levl[x][y].typ == HWALL
|| levl[x][y].typ == IRONBARS)
levl[x][y].horizontal = 1;
else if (levl[x][y].typ == LAVAPOOL)
levl[x][y].lit = 1;
else if (splev_init_present && levl[x][y].typ == ICE)
levl[x][y].icedpool = icedpools ? ICED_POOL : ICED_MOAT;
}
if (coder->lvl_is_joined)
remove_rooms(xstart, ystart, xstart + xsize, ystart + ysize);
}
if (!OV_i(mpkeepr)) {
xstart = tmpxstart;
ystart = tmpystart;
xsize = tmpxsize;
ysize = tmpysize;
}
opvar_free(mpxs);
opvar_free(mpys);
opvar_free(mpmap);
opvar_free(mpa);
opvar_free(mpkeepr);
opvar_free(mpzalign);
}
spo_jmp
void
spo_jmp(coder, lvl)
struct sp_coder *coder;
sp_lev *lvl;
{
static const char nhFunc[] = "spo_jmp";
struct opvar *tmpa;
long a;
if (!OV_pop_i(tmpa))
return;
a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(tmpa) - 1));
if ((a >= 0) && (a < lvl->n_opcodes) && (a != coder->frame->n_opcode))
coder->frame->n_opcode = a;
opvar_free(tmpa);
}
spo_conditional_jump
void
spo_conditional_jump(coder, lvl)
struct sp_coder *coder;
sp_lev *lvl;
{
static const char nhFunc[] = "spo_conditional_jump";
struct opvar *oa, *oc;
long a, c;
int test = 0;
if (!OV_pop_i(oa) || !OV_pop_i(oc))
return;
a = sp_code_jmpaddr(coder->frame->n_opcode, (OV_i(oa) - 1));
c = OV_i(oc);
switch (coder->opcode) {
default:
impossible("spo_conditional_jump: illegal opcode");
break;
case SPO_JL:
test = (c & SP_CPUFLAG_LT);
break;
case SPO_JLE:
test = (c & (SP_CPUFLAG_LT | SP_CPUFLAG_EQ));
break;
case SPO_JG:
test = (c & SP_CPUFLAG_GT);
break;
case SPO_JGE:
test = (c & (SP_CPUFLAG_GT | SP_CPUFLAG_EQ));
break;
case SPO_JE:
test = (c & SP_CPUFLAG_EQ);
break;
case SPO_JNE:
test = (c & ~SP_CPUFLAG_EQ);
break;
}
if ((test) && (a >= 0) && (a < lvl->n_opcodes)
&& (a != coder->frame->n_opcode))
coder->frame->n_opcode = a;
opvar_free(oa);
opvar_free(oc);
}
spo_var_init
void
spo_var_init(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_var_init";
struct opvar *vname;
struct opvar *arraylen;
struct opvar *vvalue;
struct splev_var *tmpvar;
struct splev_var *tmp2;
long idx;
OV_pop_s(vname);
OV_pop_i(arraylen);
if (!vname || !arraylen)
panic("no values for SPO_VAR_INIT");
tmpvar = opvar_var_defined(coder, OV_s(vname));
if (tmpvar) {
/* variable redefinition */
if (OV_i(arraylen) < 0) {
/* copy variable */
if (tmpvar->array_len) {
idx = tmpvar->array_len;
while (idx-- > 0) {
opvar_free(tmpvar->data.arrayvalues[idx]);
}
Free(tmpvar->data.arrayvalues);
} else {
opvar_free(tmpvar->data.value);
}
tmpvar->data.arrayvalues = NULL;
goto copy_variable;
} else if (OV_i(arraylen)) {
/* redefined array */
idx = tmpvar->array_len;
while (idx-- > 0) {
opvar_free(tmpvar->data.arrayvalues[idx]);
}
Free(tmpvar->data.arrayvalues);
tmpvar->data.arrayvalues = NULL;
goto create_new_array;
} else {
/* redefined single value */
OV_pop(vvalue);
if (tmpvar->svtyp != vvalue->spovartyp)
panic("redefining variable as different type");
opvar_free(tmpvar->data.value);
tmpvar->data.value = vvalue;
tmpvar->array_len = 0;
}
} else {
/* new variable definition */
tmpvar = (struct splev_var *) alloc(sizeof(struct splev_var));
tmpvar->next = coder->frame->variables;
tmpvar->name = dupstr(OV_s(vname));
coder->frame->variables = tmpvar;
if (OV_i(arraylen) < 0) {
/* copy variable */
copy_variable:
OV_pop(vvalue);
tmp2 = opvar_var_defined(coder, OV_s(vvalue));
if (!tmp2)
panic("no copyable var");
tmpvar->svtyp = tmp2->svtyp;
tmpvar->array_len = tmp2->array_len;
if (tmpvar->array_len) {
idx = tmpvar->array_len;
tmpvar->data.arrayvalues =
(struct opvar **) alloc(sizeof(struct opvar *) * idx);
while (idx-- > 0) {
tmpvar->data.arrayvalues[idx] =
opvar_clone(tmp2->data.arrayvalues[idx]);
}
} else {
tmpvar->data.value = opvar_clone(tmp2->data.value);
}
opvar_free(vvalue);
} else if (OV_i(arraylen)) {
/* new array */
create_new_array:
idx = OV_i(arraylen);
tmpvar->array_len = idx;
tmpvar->data.arrayvalues =
(struct opvar **) alloc(sizeof(struct opvar *) * idx);
while (idx-- > 0) {
OV_pop(vvalue);
if (!vvalue)
panic("no value for arrayvariable");
tmpvar->data.arrayvalues[idx] = vvalue;
}
tmpvar->svtyp = SPOVAR_ARRAY;
} else {
/* new single value */
OV_pop(vvalue);
if (!vvalue)
panic("no value for variable");
tmpvar->svtyp = OV_typ(vvalue);
tmpvar->data.value = vvalue;
tmpvar->array_len = 0;
}
}
opvar_free(vname);
opvar_free(arraylen);
}
#if 0
STATIC_OVL long
opvar_array_length(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "opvar_array_length";
struct opvar *vname;
struct splev_var *tmp;
long len = 0;
if (!coder)
return 0;
vname = splev_stack_pop(coder->stack);
if (!vname)
return 0;
if (vname->spovartyp != SPOVAR_VARIABLE)
goto pass;
tmp = coder->frame->variables;
while (tmp) {
if (!strcmp(tmp->name, OV_s(vname))) {
if ((tmp->svtyp & SPOVAR_ARRAY)) {
len = tmp->array_len;
if (len < 1)
len = 0;
}
goto pass;
}
tmp = tmp->next;
}
pass:
opvar_free(vname);
return len;
}
#endif /*0*/
spo_shuffle_array
void
spo_shuffle_array(coder)
struct sp_coder *coder;
{
static const char nhFunc[] = "spo_shuffle_array";
struct opvar *vname;
struct splev_var *tmp;
struct opvar *tmp2;
long i, j;
if (!OV_pop_s(vname))
return;
tmp = opvar_var_defined(coder, OV_s(vname));
if (!tmp || (tmp->array_len < 1)) {
opvar_free(vname);
return;
}
for (i = tmp->array_len - 1; i > 0; i--) {
if ((j = rn2(i + 1)) == i)
continue;
tmp2 = tmp->data.arrayvalues[j];
tmp->data.arrayvalues[j] = tmp->data.arrayvalues[i];
tmp->data.arrayvalues[i] = tmp2;
}
opvar_free(vname);
}
sp_level_coder
/* Special level coder, creates the special level from the sp_lev codes.
* Does not free the allocated memory.
*/
STATIC_OVL boolean
sp_level_coder(lvl)
sp_lev *lvl;
{
static const char nhFunc[] = "sp_level_coder";
unsigned long exec_opcodes = 0;
int tmpi;
long room_stack = 0;
unsigned long max_execution = SPCODER_MAX_RUNTIME;
struct sp_coder *coder =
(struct sp_coder *) alloc(sizeof (struct sp_coder));
coder->frame = frame_new(0);
coder->stack = NULL;
coder->premapped = FALSE;
coder->solidify = FALSE;
coder->check_inaccessibles = FALSE;
coder->croom = NULL;
coder->n_subroom = 1;
coder->exit_script = FALSE;
coder->lvl_is_joined = 0;
splev_init_present = FALSE;
icedpools = FALSE;
/* achievement tracking; static init would suffice except we need to
reset if #wizmakemap is used to recreate mines' end or sokoban end;
once either level is created, these values can be forgotten */
mines_prize_count = soko_prize_count = 0;
if (wizard) {
char *met = nh_getenv("SPCODER_MAX_RUNTIME");
if (met && met[0] == '1')
max_execution = (1 << 30) - 1;
}
for (tmpi = 0; tmpi <= MAX_NESTED_ROOMS; tmpi++) {
coder->tmproomlist[tmpi] = (struct mkroom *) 0;
coder->failed_room[tmpi] = FALSE;
}
shuffle_alignments();
for (tmpi = 0; tmpi < MAX_CONTAINMENT; tmpi++)
container_obj[tmpi] = NULL;
container_idx = 0;
invent_carrying_monster = NULL;
(void) memset((genericptr_t) &SpLev_Map[0][0], 0, sizeof SpLev_Map);
level.flags.is_maze_lev = 0;
xstart = 1;
ystart = 0;
xsize = COLNO - 1;
ysize = ROWNO;
while (coder->frame->n_opcode < lvl->n_opcodes && !coder->exit_script) {
coder->opcode = lvl->opcodes[coder->frame->n_opcode].opcode;
coder->opdat = lvl->opcodes[coder->frame->n_opcode].opdat;
coder->stack = coder->frame->stack;
if (exec_opcodes++ > max_execution) {
impossible("Level script is taking too much time, stopping.");
coder->exit_script = TRUE;
}
if (coder->failed_room[coder->n_subroom - 1]
&& coder->opcode != SPO_ENDROOM && coder->opcode != SPO_ROOM
&& coder->opcode != SPO_SUBROOM)
goto next_opcode;
coder->croom = coder->tmproomlist[coder->n_subroom - 1];
switch (coder->opcode) {
case SPO_NULL:
break;
case SPO_EXIT:
coder->exit_script = TRUE;
break;
case SPO_FRAME_PUSH:
spo_frame_push(coder);
break;
case SPO_FRAME_POP:
spo_frame_pop(coder);
break;
case SPO_CALL:
spo_call(coder);
break;
case SPO_RETURN:
spo_return(coder);
break;
case SPO_END_MONINVENT:
spo_end_moninvent(coder);
break;
case SPO_POP_CONTAINER:
spo_pop_container(coder);
break;
case SPO_POP: {
struct opvar *ov = splev_stack_pop(coder->stack);
opvar_free(ov);
break;
}
case SPO_PUSH:
splev_stack_push(coder->stack, opvar_clone(coder->opdat));
break;
case SPO_MESSAGE:
spo_message(coder);
break;
case SPO_MONSTER:
spo_monster(coder);
break;
case SPO_OBJECT:
spo_object(coder);
break;
case SPO_LEVEL_FLAGS:
spo_level_flags(coder);
break;
case SPO_INITLEVEL:
spo_initlevel(coder);
break;
case SPO_ENGRAVING:
spo_engraving(coder);
break;
case SPO_MINERALIZE:
spo_mineralize(coder);
break;
case SPO_SUBROOM:
case SPO_ROOM:
if (!coder->failed_room[coder->n_subroom - 1]) {
spo_room(coder);
} else
room_stack++;
break;
case SPO_ENDROOM:
if (coder->failed_room[coder->n_subroom - 1]) {
if (!room_stack)
spo_endroom(coder);
else
room_stack--;
} else {
spo_endroom(coder);
}
break;
case SPO_DOOR:
spo_door(coder);
break;
case SPO_STAIR:
spo_stair(coder);
break;
case SPO_LADDER:
spo_ladder(coder);
break;
case SPO_GRAVE:
spo_grave(coder);
break;
case SPO_ALTAR:
spo_altar(coder);
break;
case SPO_SINK:
case SPO_POOL:
case SPO_FOUNTAIN:
spo_feature(coder);
break;
case SPO_TRAP:
spo_trap(coder);
break;
case SPO_GOLD:
spo_gold(coder);
break;
case SPO_CORRIDOR:
spo_corridor(coder);
break;
case SPO_TERRAIN:
spo_terrain(coder);
break;
case SPO_REPLACETERRAIN:
spo_replace_terrain(coder);
break;
case SPO_LEVREGION:
spo_levregion(coder);
break;
case SPO_REGION:
spo_region(coder);
break;
case SPO_DRAWBRIDGE:
spo_drawbridge(coder);
break;
case SPO_MAZEWALK:
spo_mazewalk(coder);
break;
case SPO_NON_PASSWALL:
case SPO_NON_DIGGABLE:
spo_wall_property(coder);
break;
case SPO_ROOM_DOOR:
spo_room_door(coder);
break;
case SPO_WALLIFY:
spo_wallify(coder);
break;
case SPO_COPY: {
struct opvar *a = splev_stack_pop(coder->stack);
splev_stack_push(coder->stack, opvar_clone(a));
splev_stack_push(coder->stack, opvar_clone(a));
opvar_free(a);
break;
}
case SPO_DEC: {
struct opvar *a;
if (!OV_pop_i(a))
break;
OV_i(a)--;
splev_stack_push(coder->stack, a);
break;
}
case SPO_INC: {
struct opvar *a;
if (!OV_pop_i(a))
break;
OV_i(a)++;
splev_stack_push(coder->stack, a);
break;
}
case SPO_MATH_SIGN: {
struct opvar *a;
if (!OV_pop_i(a))
break;
OV_i(a) = ((OV_i(a) < 0) ? -1 : ((OV_i(a) > 0) ? 1 : 0));
splev_stack_push(coder->stack, a);
break;
}
case SPO_MATH_ADD: {
struct opvar *a, *b;
if (!OV_pop(b) || !OV_pop(a))
break;
if (OV_typ(b) == OV_typ(a)) {
if (OV_typ(a) == SPOVAR_INT) {
OV_i(a) = OV_i(a) + OV_i(b);
splev_stack_push(coder->stack, a);
opvar_free(b);
} else if (OV_typ(a) == SPOVAR_STRING) {
struct opvar *c;
char *tmpbuf = (char *) alloc(strlen(OV_s(a))
+ strlen(OV_s(b)) + 1);
(void) sprintf(tmpbuf, "%s%s", OV_s(a), OV_s(b));
c = opvar_new_str(tmpbuf);
splev_stack_push(coder->stack, c);
opvar_free(a);
opvar_free(b);
Free(tmpbuf);
} else {
splev_stack_push(coder->stack, a);
opvar_free(b);
impossible("adding weird types");
}
} else {
splev_stack_push(coder->stack, a);
opvar_free(b);
impossible("adding different types");
}
break;
}
case SPO_MATH_SUB: {
struct opvar *a, *b;
if (!OV_pop_i(b) || !OV_pop_i(a))
break;
OV_i(a) = OV_i(a) - OV_i(b);
splev_stack_push(coder->stack, a);
opvar_free(b);
break;
}
case SPO_MATH_MUL: {
struct opvar *a, *b;
if (!OV_pop_i(b) || !OV_pop_i(a))
break;
OV_i(a) = OV_i(a) * OV_i(b);
splev_stack_push(coder->stack, a);
opvar_free(b);
break;
}
case SPO_MATH_DIV: {
struct opvar *a, *b;
if (!OV_pop_i(b) || !OV_pop_i(a))
break;
if (OV_i(b) >= 1) {
OV_i(a) = OV_i(a) / OV_i(b);
} else {
OV_i(a) = 0;
}
splev_stack_push(coder->stack, a);
opvar_free(b);
break;
}
case SPO_MATH_MOD: {
struct opvar *a, *b;
if (!OV_pop_i(b) || !OV_pop_i(a))
break;
if (OV_i(b) > 0) {
OV_i(a) = OV_i(a) % OV_i(b);
} else {
OV_i(a) = 0;
}
splev_stack_push(coder->stack, a);
opvar_free(b);
break;
}
case SPO_CMP: {
struct opvar *a;
struct opvar *b;
struct opvar *c;
long val = 0;
OV_pop(b);
OV_pop(a);
if (!a || !b) {
impossible("spo_cmp: no values in stack");
break;
}
if (OV_typ(a) != OV_typ(b)) {
impossible("spo_cmp: trying to compare differing datatypes");
break;
}
switch (OV_typ(a)) {
case SPOVAR_COORD:
case SPOVAR_REGION:
case SPOVAR_MAPCHAR:
case SPOVAR_MONST:
case SPOVAR_OBJ:
case SPOVAR_INT:
if (OV_i(b) > OV_i(a))
val |= SP_CPUFLAG_LT;
if (OV_i(b) < OV_i(a))
val |= SP_CPUFLAG_GT;
if (OV_i(b) == OV_i(a))
val |= SP_CPUFLAG_EQ;
c = opvar_new_int(val);
break;
case SPOVAR_STRING:
c = opvar_new_int(!strcmp(OV_s(b), OV_s(a))
? SP_CPUFLAG_EQ
: 0);
break;
default:
c = opvar_new_int(0);
break;
}
splev_stack_push(coder->stack, c);
opvar_free(a);
opvar_free(b);
break;
}
case SPO_JMP:
spo_jmp(coder, lvl);
break;
case SPO_JL:
case SPO_JLE:
case SPO_JG:
case SPO_JGE:
case SPO_JE:
case SPO_JNE:
spo_conditional_jump(coder, lvl);
break;
case SPO_RN2: {
struct opvar *tmpv;
struct opvar *t;
if (!OV_pop_i(tmpv))
break;
t = opvar_new_int((OV_i(tmpv) > 1) ? rn2(OV_i(tmpv)) : 0);
splev_stack_push(coder->stack, t);
opvar_free(tmpv);
break;
}
case SPO_DICE: {
struct opvar *a, *b, *t;
if (!OV_pop_i(b) || !OV_pop_i(a))
break;
if (OV_i(b) < 1)
OV_i(b) = 1;
if (OV_i(a) < 1)
OV_i(a) = 1;
t = opvar_new_int(d(OV_i(a), OV_i(b)));
splev_stack_push(coder->stack, t);
opvar_free(a);
opvar_free(b);
break;
}
case SPO_MAP:
spo_map(coder);
break;
case SPO_VAR_INIT:
spo_var_init(coder);
break;
case SPO_SHUFFLE_ARRAY:
spo_shuffle_array(coder);
break;
case SPO_SEL_ADD: /* actually, logical or */
{
struct opvar *sel1, *sel2, *pt;
if (!OV_pop_typ(sel1, SPOVAR_SEL))
panic("no sel1 for add");
if (!OV_pop_typ(sel2, SPOVAR_SEL))
panic("no sel2 for add");
pt = selection_logical_oper(sel1, sel2, '|');
opvar_free(sel1);
opvar_free(sel2);
splev_stack_push(coder->stack, pt);
break;
}
case SPO_SEL_COMPLEMENT: {
struct opvar *sel, *pt;
if (!OV_pop_typ(sel, SPOVAR_SEL))
panic("no sel for not");
pt = selection_not(sel);
opvar_free(sel);
splev_stack_push(coder->stack, pt);
break;
}
case SPO_SEL_FILTER: /* sorta like logical and */
{
struct opvar *filtertype;
if (!OV_pop_i(filtertype))
panic("no sel filter type");
switch (OV_i(filtertype)) {
case SPOFILTER_PERCENT: {
struct opvar *tmp1, *sel;
if (!OV_pop_i(tmp1))
panic("no sel filter percent");
if (!OV_pop_typ(sel, SPOVAR_SEL))
panic("no sel filter");
selection_filter_percent(sel, OV_i(tmp1));
splev_stack_push(coder->stack, sel);
opvar_free(tmp1);
break;
}
case SPOFILTER_SELECTION: /* logical and */
{
struct opvar *pt, *sel1, *sel2;
if (!OV_pop_typ(sel1, SPOVAR_SEL))
panic("no sel filter sel1");
if (!OV_pop_typ(sel2, SPOVAR_SEL))
panic("no sel filter sel2");
pt = selection_logical_oper(sel1, sel2, '&');
splev_stack_push(coder->stack, pt);
opvar_free(sel1);
opvar_free(sel2);
break;
}
case SPOFILTER_MAPCHAR: {
struct opvar *pt, *tmp1, *sel;
if (!OV_pop_typ(sel, SPOVAR_SEL))
panic("no sel filter");
if (!OV_pop_typ(tmp1, SPOVAR_MAPCHAR))
panic("no sel filter mapchar");
pt = selection_filter_mapchar(sel, tmp1);
splev_stack_push(coder->stack, pt);
opvar_free(tmp1);
opvar_free(sel);
break;
}
default:
panic("unknown sel filter type");
}
opvar_free(filtertype);
break;
}
case SPO_SEL_POINT: {
struct opvar *tmp;
struct opvar *pt = selection_opvar((char *) 0);
schar x, y;
if (!OV_pop_c(tmp))
panic("no ter sel coord");
get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp));
selection_setpoint(x, y, pt, 1);
splev_stack_push(coder->stack, pt);
opvar_free(tmp);
break;
}
case SPO_SEL_RECT:
case SPO_SEL_FILLRECT: {
struct opvar *tmp, *pt = selection_opvar((char *) 0);
schar x, y, x1, y1, x2, y2;
if (!OV_pop_r(tmp))
panic("no ter sel region");
x1 = min(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp)));
y1 = min(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp)));
x2 = max(SP_REGION_X1(OV_i(tmp)), SP_REGION_X2(OV_i(tmp)));
y2 = max(SP_REGION_Y1(OV_i(tmp)), SP_REGION_Y2(OV_i(tmp)));
get_location(&x1, &y1, ANY_LOC, coder->croom);
get_location(&x2, &y2, ANY_LOC, coder->croom);
x1 = (x1 < 0) ? 0 : x1;
y1 = (y1 < 0) ? 0 : y1;
x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
if (coder->opcode == SPO_SEL_RECT) {
for (x = x1; x <= x2; x++) {
selection_setpoint(x, y1, pt, 1);
selection_setpoint(x, y2, pt, 1);
}
for (y = y1; y <= y2; y++) {
selection_setpoint(x1, y, pt, 1);
selection_setpoint(x2, y, pt, 1);
}
} else {
for (x = x1; x <= x2; x++)
for (y = y1; y <= y2; y++)
selection_setpoint(x, y, pt, 1);
}
splev_stack_push(coder->stack, pt);
opvar_free(tmp);
break;
}
case SPO_SEL_LINE: {
struct opvar *tmp = NULL, *tmp2 = NULL,
*pt = selection_opvar((char *) 0);
schar x1, y1, x2, y2;
if (!OV_pop_c(tmp))
panic("no ter sel linecoord1");
if (!OV_pop_c(tmp2))
panic("no ter sel linecoord2");
get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp));
get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2));
x1 = (x1 < 0) ? 0 : x1;
y1 = (y1 < 0) ? 0 : y1;
x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
selection_do_line(x1, y1, x2, y2, pt);
splev_stack_push(coder->stack, pt);
opvar_free(tmp);
opvar_free(tmp2);
break;
}
case SPO_SEL_RNDLINE: {
struct opvar *tmp = NULL, *tmp2 = NULL, *tmp3,
*pt = selection_opvar((char *) 0);
schar x1, y1, x2, y2;
if (!OV_pop_i(tmp3))
panic("no ter sel randline1");
if (!OV_pop_c(tmp))
panic("no ter sel randline2");
if (!OV_pop_c(tmp2))
panic("no ter sel randline3");
get_location_coord(&x1, &y1, ANY_LOC, coder->croom, OV_i(tmp));
get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(tmp2));
x1 = (x1 < 0) ? 0 : x1;
y1 = (y1 < 0) ? 0 : y1;
x2 = (x2 >= COLNO) ? COLNO - 1 : x2;
y2 = (y2 >= ROWNO) ? ROWNO - 1 : y2;
selection_do_randline(x1, y1, x2, y2, OV_i(tmp3), 12, pt);
splev_stack_push(coder->stack, pt);
opvar_free(tmp);
opvar_free(tmp2);
opvar_free(tmp3);
break;
}
case SPO_SEL_GROW: {
struct opvar *dirs, *pt;
if (!OV_pop_i(dirs))
panic("no dirs for grow");
if (!OV_pop_typ(pt, SPOVAR_SEL))
panic("no selection for grow");
selection_do_grow(pt, OV_i(dirs));
splev_stack_push(coder->stack, pt);
opvar_free(dirs);
break;
}
case SPO_SEL_FLOOD: {
struct opvar *tmp;
schar x, y;
if (!OV_pop_c(tmp))
panic("no ter sel flood coord");
get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(tmp));
if (isok(x, y)) {
struct opvar *pt = selection_opvar((char *) 0);
set_selection_floodfillchk(floodfillchk_match_under);
floodfillchk_match_under_typ = levl[x][y].typ;
selection_floodfill(pt, x, y, FALSE);
splev_stack_push(coder->stack, pt);
}
opvar_free(tmp);
break;
}
case SPO_SEL_RNDCOORD: {
struct opvar *pt;
schar x, y;
if (!OV_pop_typ(pt, SPOVAR_SEL))
panic("no selection for rndcoord");
if (selection_rndcoord(pt, &x, &y, FALSE)) {
x -= xstart;
y -= ystart;
}
splev_stack_push(coder->stack, opvar_new_coord(x, y));
opvar_free(pt);
break;
}
case SPO_SEL_ELLIPSE: {
struct opvar *filled, *xaxis, *yaxis, *pt;
struct opvar *sel = selection_opvar((char *) 0);
schar x, y;
if (!OV_pop_i(filled))
panic("no filled for ellipse");
if (!OV_pop_i(yaxis))
panic("no yaxis for ellipse");
if (!OV_pop_i(xaxis))
panic("no xaxis for ellipse");
if (!OV_pop_c(pt))
panic("no pt for ellipse");
get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(pt));
selection_do_ellipse(sel, x, y, OV_i(xaxis), OV_i(yaxis),
OV_i(filled));
splev_stack_push(coder->stack, sel);
opvar_free(filled);
opvar_free(yaxis);
opvar_free(xaxis);
opvar_free(pt);
break;
}
case SPO_SEL_GRADIENT: {
struct opvar *gtyp, *glim, *mind, *maxd, *gcoord, *coord2;
struct opvar *sel;
schar x, y, x2, y2;
if (!OV_pop_i(gtyp))
panic("no gtyp for grad");
if (!OV_pop_i(glim))
panic("no glim for grad");
if (!OV_pop_c(coord2))
panic("no coord2 for grad");
if (!OV_pop_c(gcoord))
panic("no coord for grad");
if (!OV_pop_i(maxd))
panic("no maxd for grad");
if (!OV_pop_i(mind))
panic("no mind for grad");
get_location_coord(&x, &y, ANY_LOC, coder->croom, OV_i(gcoord));
get_location_coord(&x2, &y2, ANY_LOC, coder->croom, OV_i(coord2));
sel = selection_opvar((char *) 0);
selection_do_gradient(sel, x, y, x2, y2, OV_i(gtyp), OV_i(mind),
OV_i(maxd), OV_i(glim));
splev_stack_push(coder->stack, sel);
opvar_free(gtyp);
opvar_free(glim);
opvar_free(gcoord);
opvar_free(coord2);
opvar_free(maxd);
opvar_free(mind);
break;
}
default:
panic("sp_level_coder: Unknown opcode %i", coder->opcode);
}
next_opcode:
coder->frame->n_opcode++;
} /*while*/
link_doors_rooms();
fill_rooms();
remove_boundary_syms();
if (coder->check_inaccessibles)
ensure_way_out();
/* FIXME: Ideally, we want this call to only cover areas of the map
* which were not inserted directly by the special level file (see
* the insect legs on Baalzebub's level, for instance). Since that
* is currently not possible, we overload the corrmaze flag for this
* purpose.
*/
if (!level.flags.corrmaze)
wallification(1, 0, COLNO - 1, ROWNO - 1);
count_features();
if (coder->solidify)
solidify_map();
/* This must be done before sokoban_detect(),
* otherwise branch stairs won't be premapped. */
fixup_special();
if (coder->premapped)
sokoban_detect();
if (coder->frame) {
struct sp_frame *tmpframe;
do {
tmpframe = coder->frame->next;
frame_del(coder->frame);
coder->frame = tmpframe;
} while (coder->frame);
}
Free(coder);
return TRUE;
}
load_special
/*
* General loader
*/
boolean
load_special(name)
const char *name;
{
dlb *fd;
sp_lev *lvl = NULL;
boolean result = FALSE;
struct version_info vers_info;
fd = dlb_fopen(name, RDBMODE);
if (!fd)
return FALSE;
Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
if (!check_version(&vers_info, name, TRUE)) {
(void) dlb_fclose(fd);
goto give_up;
}
lvl = (sp_lev *) alloc(sizeof (sp_lev));
result = sp_level_loader(fd, lvl);
(void) dlb_fclose(fd);
if (result)
result = sp_level_coder(lvl);
sp_level_free(lvl);
Free(lvl);
give_up:
return result;
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/*sp_lev.c*/