]> granicus.if.org Git - nethack/commitdiff
Merge branch 'NetHack-3.6'
authornhmall <nhmall@nethack.org>
Wed, 2 Oct 2019 00:44:57 +0000 (20:44 -0400)
committernhmall <nhmall@nethack.org>
Wed, 2 Oct 2019 00:44:57 +0000 (20:44 -0400)
1  2 
doc/Guidebook.mn
doc/Guidebook.tex
include/decl.h
include/extern.h
include/flag.h
src/cmd.c
src/decl.c
src/options.c
src/pickup.c

index e9556fd690981a5427e3e710290e6f4cb591ad2d,9fb47b12eeac4e83174bda5469660965fa99c124..d50b20b29ecfce10f9731708bb0b3c62f4793d7b
  .ds h0 "NetHack Guidebook
  .ds h1
  .ds h2 %
 -.ds vr "NetHack 3.6
 +.ds vr "NetHack 3.7
  .ds f0 "\*(vr
  .ds f1
- .ds f2 "July 9, 2019
+ .ds f2 "October 1, 2019
  .
  .\" A note on some special characters:
  .\" \(lq = left double quote
Simple merge
diff --cc include/decl.h
index c9f769e86f986f0cdce1b3c6daec9e52bf1c4d89,974af0f109c10a0cc36d95be8f848945e737fea8..66ada6cae4e405613b29753a8c0e8f718d830de0
@@@ -474,797 -460,6 +474,798 @@@ struct early_opt 
      boolean valallowed;
  };
  
 +/* special key functions */
 +enum nh_keyfunc {
 +    NHKF_ESC = 0,
 +    NHKF_DOAGAIN,
 +
 +    NHKF_REQMENU,
 +
 +    /* run ... clicklook need to be in a continuous block */
 +    NHKF_RUN,
 +    NHKF_RUN2,
 +    NHKF_RUSH,
 +    NHKF_FIGHT,
 +    NHKF_FIGHT2,
 +    NHKF_NOPICKUP,
 +    NHKF_RUN_NOPICKUP,
 +    NHKF_DOINV,
 +    NHKF_TRAVEL,
 +    NHKF_CLICKLOOK,
 +
 +    NHKF_REDRAW,
 +    NHKF_REDRAW2,
 +    NHKF_GETDIR_SELF,
 +    NHKF_GETDIR_SELF2,
 +    NHKF_GETDIR_HELP,
 +    NHKF_COUNT,
 +    NHKF_GETPOS_SELF,
 +    NHKF_GETPOS_PICK,
 +    NHKF_GETPOS_PICK_Q,  /* quick */
 +    NHKF_GETPOS_PICK_O,  /* once */
 +    NHKF_GETPOS_PICK_V,  /* verbose */
 +    NHKF_GETPOS_SHOWVALID,
 +    NHKF_GETPOS_AUTODESC,
 +    NHKF_GETPOS_MON_NEXT,
 +    NHKF_GETPOS_MON_PREV,
 +    NHKF_GETPOS_OBJ_NEXT,
 +    NHKF_GETPOS_OBJ_PREV,
 +    NHKF_GETPOS_DOOR_NEXT,
 +    NHKF_GETPOS_DOOR_PREV,
 +    NHKF_GETPOS_UNEX_NEXT,
 +    NHKF_GETPOS_UNEX_PREV,
 +    NHKF_GETPOS_INTERESTING_NEXT,
 +    NHKF_GETPOS_INTERESTING_PREV,
 +    NHKF_GETPOS_VALID_NEXT,
 +    NHKF_GETPOS_VALID_PREV,
 +    NHKF_GETPOS_HELP,
 +    NHKF_GETPOS_MENU,
 +    NHKF_GETPOS_LIMITVIEW,
 +    NHKF_GETPOS_MOVESKIP,
 +
 +    NUM_NHKF
 +};
 +
 +/* commands[] is used to directly access cmdlist[] instead of looping
 +   through it to find the entry for a given input character;
 +   move_X is the character used for moving one step in direction X;
 +   alphadirchars corresponds to old sdir,
 +   dirchars corresponds to ``iflags.num_pad ? ndir : sdir'';
 +   pcHack_compat and phone_layout only matter when num_pad is on,
 +   swap_yz only matters when it's off */
 +struct cmd {
 +    unsigned serialno;     /* incremented after each update */
 +    boolean num_pad;       /* same as iflags.num_pad except during updates */
 +    boolean pcHack_compat; /* for numpad:  affects 5, M-5, and M-0 */
 +    boolean phone_layout;  /* inverted keypad:  1,2,3 above, 7,8,9 below */
 +    boolean swap_yz;       /* QWERTZ keyboards; use z to move NW, y to zap */
 +    char move_W, move_NW, move_N, move_NE, move_E, move_SE, move_S, move_SW;
 +    const char *dirchars;      /* current movement/direction characters */
 +    const char *alphadirchars; /* same as dirchars if !numpad */
 +    const struct ext_func_tab *commands[256]; /* indexed by input character */
 +    char spkeys[NUM_NHKF];
 +};
 +
 +
 +#define ENTITIES 2
 +
 +struct entity {
 +    struct monst *emon;     /* youmonst for the player */
 +    struct permonst *edata; /* must be non-zero for record to be valid */
 +    int ex, ey;
 +};
 +
 +/* these probably ought to be generated by makedefs, like LAST_GEM */
 +#define FIRST_GEM DILITHIUM_CRYSTAL
 +#define FIRST_AMULET AMULET_OF_ESP
 +#define LAST_AMULET AMULET_OF_YENDOR
 +
 +struct valuable_data {
 +    long count;
 +    int typ;
 +};
 +
 +struct val_list {
 +    struct valuable_data *list;
 +    int size;
 +};
 +
 +/* at most one of `door' and `box' should be non-null at any given time */
 +struct xlock_s {
 +    struct rm *door;
 +    struct obj *box;
 +    int picktyp, /* key|pick|card for unlock, sharp vs blunt for #force */
 +        chance, usedtime;
 +    boolean magic_key;
 +};
 +
 +struct trapinfo {
 +    struct obj *tobj;
 +    xchar tx, ty;
 +    int time_needed;
 +    boolean force_bungle;
 +};
 +
 +typedef struct {
 +    xchar gnew; /* perhaps move this bit into the rm structure. */
 +    int glyph;
 +} gbuf_entry;
 +
 +enum vanq_order_modes {
 +    VANQ_MLVL_MNDX = 0,
 +    VANQ_MSTR_MNDX,
 +    VANQ_ALPHA_SEP,
 +    VANQ_ALPHA_MIX,
 +    VANQ_MCLS_HTOL,
 +    VANQ_MCLS_LTOH,
 +    VANQ_COUNT_H_L,
 +    VANQ_COUNT_L_H,
 +
 +    NUM_VANQ_ORDER_MODES
 +};
 +
 +struct rogueroom {
 +    xchar rlx, rly;
 +    xchar dx, dy;
 +    boolean real;
 +    uchar doortable;
 +    int nroom; /* Only meaningful for "real" rooms */
 +};
 +
 +typedef struct ls_t {
 +    struct ls_t *next;
 +    xchar x, y;  /* source's position */
 +    short range; /* source's current range */
 +    short flags;
 +    short type;  /* type of light source */
 +    anything id; /* source's identifier */
 +} light_source;
 +
 +struct container {
 +    struct container *next;
 +    xchar x, y;
 +    short what;
 +    genericptr_t list;
 +};
 +
 +enum bubble_contains_types {
 +    CONS_OBJ = 0,
 +    CONS_MON,
 +    CONS_HERO,
 +    CONS_TRAP
 +};
 +
 +#define MAX_BMASK 4
 +
 +struct bubble {
 +    xchar x, y;   /* coordinates of the upper left corner */
 +    schar dx, dy; /* the general direction of the bubble's movement */
 +    uchar bm[MAX_BMASK + 2];    /* bubble bit mask */
 +    struct bubble *prev, *next; /* need to traverse the list up and down */
 +    struct container *cons;
 +};
 +
 +struct musable {
 +    struct obj *offensive;
 +    struct obj *defensive;
 +    struct obj *misc;
 +    int has_offense, has_defense, has_misc;
 +    /* =0, no capability; otherwise, different numbers.
 +     * If it's an object, the object is also set (it's 0 otherwise).
 +     */
 +};
 +
 +struct h2o_ctx {
 +    int dkn_boom, unk_boom; /* track dknown, !dknown separately */
 +    boolean ctx_valid;
 +};
 +
 +struct launchplace {
 +    struct obj *obj;
 +    xchar x, y;
 +};
 +
 +struct repo { /* repossession context */
 +    struct monst *shopkeeper;
 +    coord location;
 +};
 +
 +/* from options.c */
 +#define MAX_MENU_MAPPED_CMDS 32 /* some number */
 +
 +/* player selection constants */
 +#define BP_ALIGN 0
 +#define BP_GEND 1
 +#define BP_RACE 2
 +#define BP_ROLE 3
 +#define NUM_BP 4
 +
 +#define NUM_ROLES (13)
 +struct role_filter {
 +    boolean roles[NUM_ROLES+1];
 +    short mask;
 +};
 +
 +/* instance_globals holds engine state that does not need to be
 + * persisted upon game exit.  The initialization state is well defined
 + * an set in decl.c during early early engine initialization.
 + *
 + * unlike instance_flags, values in the structure can be of any type. */
 +
 +#define BSIZE 20
 +#define WIZKIT_MAX 128
 +#define CVT_BUF_SIZE 64
 +
 +struct instance_globals {
 +
 +    /* apply.c */
 +    int jumping_is_magic; /* current jump result of magic */
 +    int polearm_range_min;
 +    int polearm_range_max;
 +    struct trapinfo trapinfo;
 +
 +    /* artifcat.c */
 +    int spec_dbon_applies; /* coordinate effects from spec_dbon() with
 +                              messages in artifact_hit() */
 +    /* flags including which artifacts have already been created */
 +    boolean artiexist[1 + NROFARTIFACTS + 1];
 +    /* and a discovery list for them (no dummy first entry here) */
 +    xchar artidisco[NROFARTIFACTS];
 +    int mkot_trap_warn_count;
 +
 +    /* botl.c */
 +    int mrank_sz; /* loaded by max_rank_sz */
 +    struct istat_s blstats[2][MAXBLSTATS];
 +    boolean blinit;
 +    boolean update_all;
 +    boolean valset[MAXBLSTATS];
 +#ifdef STATUS_HILITES
 +    long bl_hilite_moves;
 +#endif
 +    unsigned long cond_hilites[BL_ATTCLR_MAX];
 +    int now_or_before_idx;   /* 0..1 for array[2][] first index */
 +
 +    /* cmd.c */
 +    struct cmd Cmd; /* flag.h */
 +    /* Provide a means to redo the last command.  The flag `in_doagain' is set
 +     * to true while redoing the command.  This flag is tested in commands that
 +     * require additional input (like `throw' which requires a thing and a
 +     * direction), and the input prompt is not shown.  Also, while in_doagain is
 +     * TRUE, no keystrokes can be saved into the saveq.
 +     */
 +    char pushq[BSIZE];
 +    char saveq[BSIZE];
 +    int phead;
 +    int ptail;
 +    int shead;
 +    int stail;
 +    coord clicklook_cc;
 +    winid en_win;
 +    boolean en_via_menu;
 +    int last_multi;
 +
 +    /* dbridge.c */
 +    struct entity occupants[ENTITIES];
 +
 +    /* decl.c */
 +    int NDECL((*occupation));
 +    int NDECL((*afternmv));
 +    const char *hname; /* name of the game (argv[0] of main) */
 +    int hackpid; /* current process id */
 +    char chosen_windowtype[WINTYPELEN];
 +    int bases[MAXOCLASSES];
 +    int multi;
 +    const char *multi_reason;
 +    int nroom;
 +    int nsubroom;
 +    int occtime;
 +    int warn_obj_cnt; /* count of monsters meeting criteria */
 +    int x_maze_max;
 +    int y_maze_max;
 +    int otg_temp; /* used by object_to_glyph() [otg] */
 +    int in_doagain;
 +    stairway dnstair; /* stairs down */
 +    stairway upstair; /* stairs up */
 +    stairway dnladder; /* ladder down */
 +    stairway upladder; /* ladder up */
 +    int smeq[MAXNROFROOMS + 1];
 +    int doorindex;
 +    char *save_cm;
 +    long done_money;
 +    long domove_attempting;
 +    long domove_succeeded;
 +#define DOMOVE_WALK         0x00000001
 +#define DOMOVE_RUSH         0x00000002
 +    const char *nomovemsg;
 +    char plname[PL_NSIZ]; /* player name */
 +    char pl_character[PL_CSIZ];
 +    char pl_race; /* character's race */
 +    char pl_fruit[PL_FSIZ];
 +    struct fruit *ffruit;
 +    char tune[6];
 +    const char *occtxt; /* defined when occupation != NULL */
 +    schar tbx;  /* mthrowu: target x */
 +    schar tby;  /* mthrowu: target y */
 +    s_level * sp_levchn;
 +    /* for xname handling of multiple shot missile volleys:
 +       number of shots, index of current one, validity check, shoot vs throw */
 +    struct multishot m_shot;
 +    dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */
 +    stairway sstairs;
 +    dest_area updest;
 +    dest_area dndest;
 +    coord inv_pos;
 +    boolean defer_see_monsters;
 +    boolean in_mklev;
 +    boolean stoned; /* done to monsters hit by 'c' */
 +    boolean unweapon;
 +    boolean mrg_to_wielded; /* weapon picked is merged with wielded one */
 +    struct plinemsg_type *plinemsg_types;
 +    char toplines[TBUFSZ];
 +    struct mkroom *upstairs_room;
 +    struct mkroom *dnstairs_room;
 +    struct mkroom *sstairs_room;
 +    coord bhitpos; /* place where throw or zap hits or stops */
 +    boolean in_steed_dismounting;
 +    coord doors[DOORMAX];
 +    struct menucoloring *menu_colorings;
 +    schar lastseentyp[COLNO][ROWNO]; /* last seen/touched dungeon typ */
 +    struct spell spl_book[MAXSPELL + 1];
 +    struct linfo level_info[MAXLINFO];
 +    struct trap *ftrap;
 +    /* some objects need special handling during destruction or placement */
 +    struct obj *current_wand;  /* wand currently zapped/applied */
 +    struct obj *thrownobj;     /* object in flight due to throwing */
 +    struct obj *kickedobj;     /* object in flight due to kicking */
 +    struct dgn_topology dungeon_topology;
 +    struct kinfo killer;
 +    struct mkroom rooms[(MAXNROFROOMS + 1) * 2];
 +    struct mkroom *subrooms;
 +    dlevel_t level; /* level map */
 +    long moves;
 +    long monstermoves; /* moves and monstermoves diverge when player is Fast */
 +    long wailmsg;
 +    struct obj *migrating_objs; /* objects moving to another dungeon level */    
 +    struct obj *billobjs; /* objects not yet paid for */
 +#if defined(MICRO) || defined(WIN32)
 +    char hackdir[PATHLEN]; /* where rumors, help, record are */
 +#endif /* MICRO || WIN32 */
 +    struct monst youmonst;
 +    struct obj *invent;
 +    struct context_info context;
 +    char *fqn_prefix[PREFIX_COUNT];
 +    /* Windowing stuff that's really tty oriented, but present for all ports */
 +    struct tc_gbl_data tc_gbl_data; /* AS,AE, LI,CO */     
 +#if defined(UNIX) || defined(VMS)
 +    int locknum; /* max num of simultaneous users */
 +#endif
 +#ifdef DEF_PAGER
 +    char *catmore; /* default pager */
 +#endif
 +#ifdef MICRO
 +    char levels[PATHLEN]; /* where levels are */
 +#endif /* MICRO */
 +#ifdef MFLOPPY
 +    char permbones[PATHLEN]; /* where permanent copy of bones go */
 +    int ramdisk = FALSE;     /* whether to copy bones to levels or not */
 +    int saveprompt = TRUE;
 +    const char *alllevels = "levels.*";
 +    const char *allbones = "bones*.*";
 +#endif
 +    struct sinfo program_state;
 +
 +    /* dig.c */
 +
 +    boolean did_dig_msg;
 +
 +    /* display.c */
 +    gbuf_entry gbuf[ROWNO][COLNO];
 +    char gbuf_start[ROWNO];
 +    char gbuf_stop[ROWNO];
 +
 +
 +    /* do.c */
 +    boolean at_ladder;
 +    char *dfr_pre_msg;  /* pline() before level change */
 +    char *dfr_post_msg; /* pline() after level change */
 +    d_level save_dlevel;
 +
 +    /* do_name.c */
 +    struct opvar *gloc_filter_map;
 +    int gloc_filter_floodfill_match_glyph;
 +    int via_naming;
 +
 +    /* do_wear.c */
 +    /* starting equipment gets auto-worn at beginning of new game,
 +       and we don't want stealth or displacement feedback then */
 +    boolean initial_don; /* manipulated in set_wear() */
 +
 +    /* dog.c */
 +    int petname_used; /* user preferred pet name has been used */
 +    xchar gtyp;  /* type of dog's current goal */
 +    xchar gx; /* x position of dog's current goal */
 +    char  gy; /* y position of dog's current goal */
 +    char dogname[PL_PSIZ];
 +    char catname[PL_PSIZ];
 +    char horsename[PL_PSIZ];
 +    char preferred_pet; /* '\0', 'c', 'd', 'n' (none) */    
 +    struct monst *mydogs; /* monsters that went down/up together with @ */
 +    struct monst *migrating_mons; /* monsters moving to another level */
++    struct autopickup_exception *apelist;
 +    struct mvitals mvitals[NUMMONS];
 +
 +    /* dokick.c */
 +    struct rm *maploc;
 +    struct rm nowhere;
 +    const char *gate_str;
 +
 +    /* drawing */
 +    struct symsetentry symset[NUM_GRAPHICS];
 +    int currentgraphics;
 +    nhsym showsyms[SYM_MAX]; /* symbols to be displayed */
 +    nhsym l_syms[SYM_MAX];   /* loaded symbols          */
 +    nhsym r_syms[SYM_MAX];   /* rogue symbols           */
 +    nhsym warnsyms[WARNCOUNT]; /* the current warning display symbols */
 +
 +    /* dungeon.c */
 +    int n_dgns; /* number of dungeons (also used in mklev.c and do.c) */
 +    branch *branches; /* dungeon branch list */
 +    mapseen *mapseenchn; /*DUNGEON_OVERVIEW*/
 +
 +    /* eat.c */
 +    boolean force_save_hs;
 +    char *eatmbuf; /* set by cpostfx() */
 +
 +
 +    /* end.c */
 +    struct valuable_data gems[LAST_GEM + 1 - FIRST_GEM + 1]; /* +1 for glass */
 +    struct valuable_data amulets[LAST_AMULET + 1 - FIRST_AMULET];
 +    struct val_list valuables[3];
 +    int vanq_sortmode;
 +
 +    /* extralev.c */
 +    struct rogueroom r[3][3];
 +
 +    /* files.c */
 +    char wizkit[WIZKIT_MAX];
 +    int lockptr;
 +    char *config_section_chosen;
 +    char *config_section_current;
 +    int nesting;
 +    int symset_count;             /* for pick-list building only */
 +    boolean chosen_symset_start;
 +    boolean chosen_symset_end;
 +    int symset_which_set;
 +    char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */
 +#ifdef MICRO
 +    char SAVEP[SAVESIZE]; /* holds path of directory for save file */
 +#endif
 +    char bones[BONESSIZE];
 +    char lock[LOCKNAMESIZE];
 +
 +
 +    /* hack.c */
 +    anything tmp_anything;
 +    int wc; /* current weight_cap(); valid after call to inv_weight() */
 +
 +    /* invent.c */
 +    int lastinvnr;  /* 0 ... 51 (never saved&restored) */
 +    unsigned sortlootmode; /* set by sortloot() for use by sortloot_cmp(); 
 +                            * reset by sortloot when done */
 +    char *invbuf;
 +    unsigned invbufsiz;
 +    /* for perm_invent when operating on a partial inventory display, so that
 +       the persistent one doesn't get shrunk during filtering for item selection
 +       then regrown to full inventory, possibly being resized in the process */
 +    winid cached_pickinv_win;
 +    /* query objlist callback: return TRUE if obj type matches "this_type" */
 +    int this_type;
 +    /* query objlist callback: return TRUE if obj is at given location */
 +    coord only;
 +
 +    /* light.c */
 +    light_source *light_base;
 +
 +
 +    /* lock.c */
 +    struct xlock_s xlock;
 +
 +    /* makemon.c */
 +    struct {
 +        int choice_count;
 +        char mchoices[SPECIAL_PM]; /* value range is 0..127 */
 +    } rndmonst_state;
 +
 +    /* mhitm.c */
 +    boolean vis;
 +    boolean far_noise;
 +    long noisetime;
 +    struct obj *otmp;
 +    int dieroll; /* Needed for the special case of monsters wielding vorpal
 +                  * blades (rare). If we use this a lot it should probably
 +                  * be a parameter to mdamagem() instead of a global variable.
 +                  */
 +
 +    /* mhitu.c */
 +    int mhitu_dieroll;
 +
 +    /* mklev.c */
 +    xchar vault_x;
 +    xchar vault_y;
 +    boolean made_branch; /* used only during level creation */
 +
 +    /* mkmap.c */
 +    char *new_locations;
 +    int min_rx; /* rectangle bounds for regions */
 +    int max_rx;
 +    int min_ry;
 +    int max_ry; 
 +    int n_loc_filled;
 +
 +    /* mkmaze.c */
 +    lev_region bughack; /* for preserving the insect legs when wallifying
 +                         * baalz level */
 +    boolean was_waterlevel; /* ugh... this shouldn't be needed */
 +    struct bubble *bbubbles;
 +    struct bubble *ebubbles;
 +    struct trap *wportal;
 +    int xmin, ymin, xmax, ymax; /* level boundaries */
 +    boolean ransacked;
 +
 +    /* mon.c */
 +    boolean vamp_rise_msg;
 +    boolean disintegested;
 +    short *animal_list; /* list of PM values for animal monsters */
 +    int animal_list_count;
 +
 +    /* mthrowu.c */
 +    int mesg_given; /* for m_throw()/thitu() 'miss' message */
 +    struct monst *mtarget;  /* monster being shot by another monster */
 +    struct monst *marcher; /* monster that is shooting */
 +
 +    /* muse.c */
 +    boolean m_using; /* kludge to use mondided instead of killed */
 +    int trapx;
 +    int trapy;
 +    boolean zap_oseen; /* for wands which use mbhitm and are zapped at
 +                        * players.  We usually want an oseen local to
 +                        * the function, but this is impossible since the
 +                        * function mbhitm has to be compatible with the
 +                        * normal zap routines, and those routines don't
 +                        * remember who zapped the wand. */
 +    struct musable m;
 +
 +    /* nhlan.c */
 +#ifdef MAX_LAN_USERNAME
 +    char lusername[MAX_LAN_USERNAME];
 +    int lusername_size;
 +#endif
 +
 +    /* o_init.c */
 +    short disco[NUM_OBJECTS];
 +
 +    /* objname.c */
 +    /* distantname used by distant_name() to pass extra information to
 +       xname_flags(); it would be much cleaner if this were a parameter,
 +       but that would require all of the xname() and doname() calls to be
 +       modified */
 +    int distantname;
 +
 +    /* options.c */
 +    struct symsetentry *symset_list; /* files.c will populate this with
 +                                        list of available sets */
 +    /*
 +        * Allow the user to map incoming characters to various menu commands.
 +        * The accelerator list must be a valid C string.
 +        */
 +    char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
 +    char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
 +    short n_menu_mapped;
 +    boolean opt_initial;
 +    boolean opt_from_file;
 +    boolean opt_need_redraw; /* for doset() */
 +
 +    /* pickup.c */
 +    int oldcap; /* last encumberance */
 +    /* current_container is set in use_container(), to be used by the
 +       callback routines in_container() and out_container() from askchain()
 +       and use_container(). Also used by menu_loot() and container_gone(). */
 +    struct obj *current_container;
 +    boolean abort_looting;
 +    /* Value set by query_objlist() for n_or_more(). */
 +    long val_for_n_or_more;
 +    /* list of valid menu classes for query_objlist() and allow_category callback
 +       (with room for all object classes, 'u'npaid, BUCX, and terminator) */
 +    char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1];
 +    boolean class_filter;
 +    boolean bucx_filter;
 +    boolean shop_filter;
 +
 +    /* pline.c */
 +    unsigned pline_flags;
 +    char prevmsg[BUFSZ];
 +#ifdef DUMPLOG
 +    unsigned saved_pline_index;  /* slot in saved_plines[] to use next */
 +    char *saved_plines[DUMPLOG_MSG_COUNT];
 +#endif
 +    /* work buffer for You(), &c and verbalize() */
 +    char *you_buf;
 +    int you_buf_siz;
 +
 +    /* polyself.c */
 +    int sex_change_ok; /* controls whether taking on new form or becoming new
 +                          man can also change sex (ought to be an arg to
 +                          polymon() and newman() instead) */
 +
 +    /* potion.c */
 +    boolean notonhead; /* for long worms */
 +    int potion_nothing;
 +    int potion_unkn;
 +
 +    /* pray.c */
 +    /* values calculated when prayer starts, and used when completed */
 +    aligntyp p_aligntyp;
 +    int p_trouble;
 +    int p_type; /* (-1)-3: (-1)=really naughty, 3=really good */
 +
 +    /* quest.c */
 +    struct q_score quest_status;
 +
 +    /* questpgr.c */
 +    char cvt_buf[CVT_BUF_SIZE];
 +    struct qtlists qt_list;
 +#ifdef DLB
 +    struct dlb_handle *msg_file;
 +#else
 +    FILE *msg_file;
 +#endif
 +    /* used by ldrname() and neminame(), then copied into cvt_buf */
 +    char nambuf[CVT_BUF_SIZE];
 +
 +    /* read.c */
 +    boolean known;
 +
 +    /* region.c */
 +    NhRegion **regions;
 +    int n_regions;
 +    int max_regions;
 +
 +    /* restore.c */
 +    int n_ids_mapped;
 +    struct bucket *id_map;
 +    boolean restoring;
 +    struct fruit *oldfruit;
 +    long omoves;
 +
 +    /* rip.c */
 +    char **rip;
 +
 +    /* role.c */
 +    struct Role urole; /* player's role. May be munged in role_init() */
 +    struct Race urace; /* player's race. May be munged in role_init() */
 +    char role_pa[NUM_BP];
 +    char role_post_attribs;
 +    struct role_filter rfilter;
 +
 +    /* rumors.c */
 +    long true_rumor_size; /* rumor size variables are signed so that value -1
 +                            can be used as a flag */
 +    long false_rumor_size;
 +    unsigned long true_rumor_start; /* rumor start offsets are unsigned because
 +                                       they're handled via %lx format */
 +    unsigned long false_rumor_start;
 +    long true_rumor_end; /* rumor end offsets are signed because they're
 +                            compared with [dlb_]ftell() */
 +    long false_rumor_end;
 +    int oracle_flg; /* -1=>don't use, 0=>need init, 1=>init done */
 +    unsigned oracle_cnt; /* oracles are handled differently from rumors... */
 +    unsigned long *oracle_loc;
 +
 +    /* save.c */
 +    boolean havestate;
 +    unsigned ustuck_id; /* need to preserve during save */
 +    unsigned usteed_id; /* need to preserve during save */
 +
 +    /* shk.c */
 +    /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */
 +    char sell_response;
 +    int sell_how;
 +    /* can't just use sell_response='y' for auto_credit because the 'a' response
 +       shouldn't carry over from ordinary selling to credit selling */
 +    boolean auto_credit;
 +    struct repo repo;
 +   long int followmsg; /* last time of follow message */
 +
 +
 +    /* sp_lev.c */
 +    char *lev_message;
 +    lev_region *lregions;
 +    int num_lregions;
 +    /* positions touched by level elements explicitly defined in the des-file */
 +    char SpLev_Map[COLNO][ROWNO];
 +    xchar xstart, ystart;
 +    char xsize, ysize;
 +    boolean splev_init_present;
 +    boolean icedpools;
 +    int mines_prize_count;
 +    int soko_prize_count; /* achievements */
 +    struct obj *container_obj[MAX_CONTAINMENT];
 +    int container_idx;
 +    struct monst *invent_carrying_monster;
 +    aligntyp ralign[3];
 +
 +    /* spells.c */
 +    int spl_sortmode;   /* index into spl_sortchoices[] */
 +    int *spl_orderindx; /* array of g.spl_book[] indices */
 +
 +    /* teleport.c */
 +    struct obj *telescroll; /* non-null when teleporting via this scroll */
 +
 +    /* timeout.c */
 +    /* ordered timer list */
 +    struct fe *timer_base; /* "active" */
 +    unsigned long timer_id;
 +
 +    /* topten.c */
 +    winid toptenwin;
 +#ifdef UPDATE_RECORD_IN_PLACE
 +    long final_fpos;
 +#endif
 +
 +
 +    /* trap.c */
 +    int force_mintrap; /* mintrap() should take a flags argument, but for time
 +                          being we use this */
 +    /* context for water_damage(), managed by water_damage_chain();
 +        when more than one stack of potions of acid explode while processing
 +        a chain of objects, use alternate phrasing after the first message */
 +    struct h2o_ctx acid_ctx;
 +    /*
 +     * The following are used to track launched objects to
 +     * prevent them from vanishing if you are killed. They
 +     * will reappear at the launchplace in bones files.
 +     */
 +    struct launchplace launchplace;
 +
 +
 +    /* u_init.c */
 +    short nocreate;
 +    short nocreate2;
 +    short nocreate3;
 +    short nocreate4;
 +    /* uhitm.c */
 +    boolean override_confirmation; /* Used to flag attacks caused by
 +                                      Stormbringer's maliciousness. */
 +
 +    /* vision.c */
 +    char **viz_array; /* used in cansee() and couldsee() macros */
 +    char *viz_rmin;                   /* min could see indices */
 +    char *viz_rmax;                   /* max could see indices */
 +    boolean vision_full_recalc;
 +
 +    /* weapon.c */
 +    struct obj *propellor;
 +
 +    /* windows.c */
 +    struct win_choices *last_winchoice;
 +
 +    /* zap.c */
 +    int  poly_zapped;
 +    boolean obj_zapped;
 +
 +    unsigned long magic; /* validate that structure layout is preserved */
 +};
 +
 +E struct instance_globals g;
 +
 +struct const_globals {
 +    const struct obj zeroobj;      /* used to zero out a struct obj */
 +    const struct monst zeromonst;  /* used to zero out a struct monst */
 +    const anything zeroany;        /* used to zero out union any */
 +};
 +
 +E const struct const_globals cg;
 +
  #undef E
  
  #endif /* DECL_H */
Simple merge
diff --cc include/flag.h
Simple merge
diff --cc src/cmd.c
Simple merge
diff --cc src/decl.c
index e93aba9d81efb654a2f35941872cdcab55f98cab,c6e6c6039fdf638c75090205801721c2cbb66d0d..76c7a0bad3a7091469cef2b9edcf42b8bf248826
@@@ -138,608 -314,43 +138,609 @@@ const struct savefile_info default_sfin
  #endif
  };
  
 -NEARDATA struct savefile_info sfrestinfo, sfsaveinfo = {
 -#ifdef NHSTDC
 -    0x00000000UL
 -#else
 -    0x00000000L
 +NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo;
 +
 +#ifdef PANICTRACE
 +const char *ARGV0;
  #endif
 -#if defined(COMPRESS) || defined(ZLIB_COMP)
 -        | SFI1_EXTERNALCOMP
 +
 +/* support for lint.h */
 +unsigned nhUse_dummy = 0;
 +
 +#define IVMAGIC 0xdeadbeef
 +
 +#ifdef GCC_WARN
 +#pragma GCC diagnostic ignored "-Wmissing-braces"
  #endif
 -#if defined(ZEROCOMP)
 -        | SFI1_ZEROCOMP
 +
 +const struct Role urole_init_data = {
 +    { "Undefined", 0 },
 +    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
 +      { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
 +    "L", "N", "C",
 +    "Xxx", "home", "locate",
 +    NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM,
 +    0, 0, 0, 0,
 +    /* Str Int Wis Dex Con Cha */
 +    { 7, 7, 7, 7, 7, 7 },
 +    { 20, 15, 15, 20, 20, 10 },
 +    /* Init   Lower  Higher */
 +    { 10, 0, 0, 8, 1, 0 }, /* Hit points */
 +    { 2, 0, 0, 2, 0, 3 },
 +    14, /* Energy */
 +     0,
 +    10,
 +     0,
 +     0,
 +     4,
 +    A_INT,
 +     0,
 +    -3
 +};
 +
 +const struct Race urace_init_data = {
 +    "something",
 +    "undefined",
 +    "something",
 +    "Xxx",
 +    { 0, 0 },
 +    NON_PM,
 +    NON_PM,
 +    NON_PM,
 +    NON_PM,
 +    0,
 +    0,
 +    0,
 +    0,
 +    /*    Str     Int Wis Dex Con Cha */
 +    { 3, 3, 3, 3, 3, 3 },
 +    { STR18(100), 18, 18, 18, 18, 18 },
 +    /* Init   Lower  Higher */
 +    { 2, 0, 0, 2, 1, 0 }, /* Hit points */
 +    { 1, 0, 2, 0, 2, 0 }  /* Energy */
 +};
 +
 +const struct instance_globals g_init = {
 +    /* apply.c */
 +    0,  /* jumping_is_magic */
 +    -1, /* polearm_range_min */
 +    -1, /* polearm_range_max  */
 +    UNDEFINED_VALUES, /* trapinfo */
 +
 +    /* artifact.c */
 +    0,  /* spec_dbon_applies */
 +    UNDEFINED_VALUES, /* artiexist */
 +    UNDEFINED_VALUES, /* artdisco */
 +    0, /* mkot_trap_warn_count */
 +
 +    /* botl.c */
 +    0,  /* mrank_sz */
 +    UNDEFINED_VALUES, /* blstats */
 +    FALSE, /* blinit */
 +    FALSE, /* update_all */
 +    UNDEFINED_VALUES, /* valset */
 +#ifdef STATUS_HILITES
 +    0, /* bl_hilite_moves */
  #endif
 -#if defined(RLECOMP)
 -        | SFI1_RLECOMP
 +    UNDEFINED_VALUES, /* cond_hilites */
 +    0, /* now_or_before_idx */
 +
 +    /* cmd.c */
 +    UNDEFINED_VALUES, /* Cmd */
 +    UNDEFINED_VALUES, /* pushq */
 +    UNDEFINED_VALUES, /* saveq */
 +    UNDEFINED_VALUE, /* phead */
 +    UNDEFINED_VALUE, /* ptail */
 +    UNDEFINED_VALUE, /* shead */
 +    UNDEFINED_VALUE, /* stail */
 +    UNDEFINED_VALUES, /* clicklook_cc */
 +    WIN_ERR, /* en_win */
 +    FALSE, /* en_via_menu */
 +    UNDEFINED_VALUE, /* last_multi */
 +
 +    /* dbridge.c */
 +    UNDEFINED_VALUES, /* occupants */
 +
 +    /* decl.c */
 +    UNDEFINED_PTR, /* occupation */
 +    UNDEFINED_PTR, /* afternmv */
 +    UNDEFINED_PTR, /* hname */
 +    0, /* hackpid */
 +    UNDEFINED_VALUES, /* chosen_windowtype */
 +    DUMMY, /* bases */
 +    0, /* multi */
 +    NULL, /* g.multi_reason */
 +    0, /* nroom */
 +    0, /* nsubroom */
 +    0, /* occtime */
 +    0, /* warn_obj_cnt */
 +    /* maze limits must be even; masking off lowest bit guarantees that */
 +    (COLNO - 1) & ~1, /* x_maze_max */
 +    (ROWNO - 1) & ~1, /* y_maze_max */
 +    UNDEFINED_VALUE, /* otg_temp */
 +    0, /* in_doagain */
 +    DUMMY, /* dnstair */
 +    DUMMY, /* upstair */
 +    DUMMY, /* dnladder */
 +    DUMMY, /* upladder */
 +    DUMMY, /* smeq */
 +    0, /* doorindex */
 +    NULL, /* save_cm */
 +    0, /* done_money */
 +    0L, /* domove_attempting */
 +    0L, /* domove_succeeded */
 +    NULL, /* nomovemsg */
 +    DUMMY, /* plname */
 +    DUMMY, /* pl_character */
 +    '\0', /* pl_race */
 +    DUMMY, /* pl_fruit */
 +    NULL, /* ffruit */
 +    DUMMY, /* tune */
 +    NULL, /* occtxt */
 +    0, /* tbx */
 +    0, /* tby */
 +    UNDEFINED_PTR, /* sp_levchn */
 +    { 0, 0, STRANGE_OBJECT, FALSE }, /* m_shot */
 +    UNDEFINED_VALUES, /* dungeons */
 +    { 0, 0, { 0, 0 }, 0 }, /* sstairs */
 +    { 0, 0, 0, 0, 0, 0, 0, 0 }, /* updest */
 +    { 0, 0, 0, 0, 0, 0, 0, 0 }, /* dndest */
 +    { 0, 0} , /* inv_pos */
 +    FALSE, /* defer_see_monsters */
 +    FALSE, /* in_mklev */
 +    FALSE, /* stoned */
 +    FALSE, /* unweapon */
 +    FALSE, /* mrg_to_wielded */
 +    NULL, /* plinemsg_types */
 +    UNDEFINED_VALUES, /* toplines */
 +    UNDEFINED_PTR, /* upstairs_room */
 +    UNDEFINED_PTR, /* dnstairs_room */
 +    UNDEFINED_PTR, /* sstairs_room */
 +    DUMMY, /* bhitpos */
 +    FALSE, /* in_steed_dismounting */
 +    DUMMY, /* doors */
 +    NULL, /* menu_colorings */
 +    DUMMY, /* lastseentyp */
 +    DUMMY, /* spl_book */
 +    UNDEFINED_VALUES, /* level_info */
 +    NULL, /* ftrap */
 +    NULL, /* current_wand */
 +    NULL, /* thrownobj */
 +    NULL, /* kickedobj */
 +    DUMMY, /* dungeon_topology */
 +    DUMMY, /* killer */
 +    DUMMY, /* rooms */
 +    NULL, /* subrooms */
 +    UNDEFINED_VALUES, /* level */
 +    1, /* moves */
 +    1, /* monstermoves */
 +    0, /* wailmsg */
 +    NULL, /* migrating_objs */
 +    NULL, /* billobjs */
 +#if defined(MICRO) || defined(WIN32)
 +    UNDEFINED_VALUES, /* hackdir */
 +#endif /* MICRO || WIN32 */
 +    DUMMY, /* youmonst */
 +    NULL, /* invent */
 +    DUMMY, /* context */
 +    DUMMY, /* fqn_prefix */
 +    DUMMY, /* tc_gbl_data */
 +#if defined(UNIX) || defined(VMS)
 +    0, /* locknum */
  #endif
 -    ,
 -#ifdef NHSTDC
 -    0x00000000UL, 0x00000000UL
 -#else
 -    0x00000000L, 0x00000000L
 +#ifdef DEF_PAGER
 +    NULL, /* catmore */
 +#endif
 +#ifdef MICRO
 +    UNDEFINED_VALUES, /* levels */
 +#endif /* MICRO */
 +#ifdef MFLOPPY
 +    UNDEFINED_VALUES, /* permbones */
 +    FALSE,     /*ramdisk */
 +    TRUE, /* saveprompt */
 +    "levels.*", /* alllevels */
 +    "bones*.*", /* allbones */
  #endif
 +    UNDEFINED_VALUES, /* program_state */
 +
 +    /* dig.c */
 +    UNDEFINED_VALUE, /* did_dig_msg */
 +
 +    /* display.c */
 +    UNDEFINED_VALUES, /* gbuf */
 +    UNDEFINED_VALUES, /* gbuf_start */
 +    UNDEFINED_VALUES, /* gbug_stop */
 +
 +    /* do.c */
 +    FALSE, /* at_ladder */
 +    NULL, /* dfr_pre_msg */
 +    NULL, /* dfr_post_msg */
 +    { 0, 0 }, /* save_dlevel */
 +
 +    /* do_name.c */
 +    NULL, /* gloc_filter_map */
 +    UNDEFINED_VALUE, /* gloc_filter_floodfill_match_glyph */
 +    0, /* via_naming */
 +
 +    /* do_wear.c */
 +    FALSE, /* initial_don */
 +
 +    /* dog.c */
 +    0,  /* petname_used */
 +    UNDEFINED_VALUE, /* gtyp */
 +    UNDEFINED_VALUE, /* gx */
 +    UNDEFINED_VALUE, /* gy */
 +    DUMMY, /* dogname */
 +    DUMMY, /* catname */
 +    DUMMY, /* horsename */
 +    UNDEFINED_VALUE, /* preferred_pet */
 +    NULL, /* mydogs */
 +    NULL, /* migrating_mons */
++    NULL, /* apelist */
 +    UNDEFINED_VALUES, /* mvitals */
 +
 +    /* dokick.c */
 +    UNDEFINED_PTR, /* maploc */
 +    UNDEFINED_VALUES, /* nowhere */
 +    UNDEFINED_PTR, /* gate_str */
 +
 +    /* drawing.c */
 +    DUMMY, /* symset */
 +    0, /* currentgraphics */
 +    DUMMY, /* showsyms */
 +    DUMMY, /* l_syms */
 +    DUMMY, /* r_syms */
 +    DUMMY, /* warnsyms */
 +
 +    /* dungeon.c */
 +    UNDEFINED_VALUE, /* n_dgns */
 +    NULL, /* branches */
 +    NULL, /* mapseenchn */
 +
 +    /* eat.c */
 +    FALSE, /* force_save_hs */
 +    NULL, /* eatmbuf */
 +
 +    /* end.c */
 +    UNDEFINED_VALUES,
 +    UNDEFINED_VALUES,
 +    UNDEFINED_VALUES,
 +    VANQ_MLVL_MNDX,
 +
 +    /* extralev.c */
 +    UNDEFINED_VALUES,
 +
 +    /* files.c */
 +    UNDEFINED_VALUES, /* wizkit */
 +    UNDEFINED_VALUE, /* lockptr */
 +    NULL, /* config_section_chosen */
 +    NULL, /* config_section_current */
 +    0, /* nesting */
 +    0, /* symset_count */
 +    FALSE, /* chosen_symset_start */
 +    FALSE, /* chosen_symset_end */
 +    0, /* symset_which_set */
 +    DUMMY, /* SAVEF */
 +#ifdef MICRO
 +    DUMMY, /* SAVEP */
 +#endif
 +    BONESINIT, /* bones */
 +    LOCKNAMEINIT, /* lock */
 +
 +
 +    /* hack.c */
 +    UNDEFINED_VALUES,
 +    UNDEFINED_VALUE,
 +
 +    /* invent.c */
 +    51, /* lastinvr */
 +    0, /* sortloogmode */
 +    NULL, /* invbuf */
 +    0, /* inbufsize */
 +    WIN_ERR, /* cached_pickinv_win */
 +    UNDEFINED_VALUE,
 +    UNDEFINED_VALUES,
 +
 +    /* light.c */
 +    NULL, /* light_source */
 +
 +    /* lock.c */
 +    UNDEFINED_VALUES,
 +
 +    /* makemon.c */
 +    { -1, /* choice_count */
 +     { 0 } }, /* mchoices */
 +
 +    /* mhitm.c */
 +    UNDEFINED_VALUE, /* vis */
 +    UNDEFINED_VALUE, /* far_noise */
 +    UNDEFINED_VALUE, /* noisetime */
 +    UNDEFINED_PTR, /* otmp */
 +    UNDEFINED_VALUE, /* dieroll */
 +
 +    /* mhitu.c */
 +    UNDEFINED_VALUE, /* mhitu_dieroll */
 +
 +    /* mklev.c */
 +    UNDEFINED_VALUE, /* vault_x */
 +    UNDEFINED_VALUE, /* vault_y */
 +    UNDEFINED_VALUE, /* made_branch */
 +
 +    /* mkmap.c */
 +    UNDEFINED_PTR, /* new_locations */
 +    UNDEFINED_VALUE, /* min_rx */
 +    UNDEFINED_VALUE, /* max_rx */
 +    UNDEFINED_VALUE, /* min_ry */
 +    UNDEFINED_VALUE, /* max_ry */
 +    UNDEFINED_VALUE, /* n_loc_filled */
 +
 +    /* mkmaze.c */
 +    { {COLNO, ROWNO, 0, 0}, {COLNO, ROWNO, 0, 0} }, /* bughack */
 +    UNDEFINED_VALUE, /* was_waterlevel */
 +    UNDEFINED_PTR, /* bbubbles */
 +    UNDEFINED_PTR, /* ebubbles */
 +    UNDEFINED_PTR, /* wportal */
 +    UNDEFINED_VALUE, /* xmin */
 +    UNDEFINED_VALUE, /* ymin */
 +    UNDEFINED_VALUE, /* xmax */
 +    UNDEFINED_VALUE, /* ymax */
 +    0, /* ransacked */
 +
 +    /* mon.c */
 +    UNDEFINED_VALUE, /* vamp_rise_msg */
 +    UNDEFINED_VALUE, /* disintegested */
 +    NULL, /* animal_list */
 +    UNDEFINED_VALUE, /* animal_list_count */
 +
 +    /* mthrowu.c */
 +    UNDEFINED_VALUE, /* mesg_given */
 +    NULL, /* mtarget */
 +    NULL, /* marcher */
 +
 +    /* muse.c */
 +    FALSE, /* m_using */
 +    UNDEFINED_VALUE, /* trapx */
 +    UNDEFINED_VALUE, /* trapy */
 +    UNDEFINED_VALUE, /* zap_oseen */
 +    UNDEFINED_VALUES, /* m */
 +
 +    /* nhlan.c */
 +#ifdef MAX_LAN_USERNAME
 +    UNDEFINED_VALUES, /* lusername */
 +    MAX_LAN_USERNAME, /* lusername_size */
 +#endif /* MAX_LAN_USERNAME */
 +
 +    /* o_init.c */
 +    DUMMY, /* disco */
 +
 +    /* objname.c */
 +    0, /* distantname */
 +
 +    /* options.c */
 +    NULL, /* symset_list */
 +    UNDEFINED_VALUES, /* mapped_menu_cmds */
 +    UNDEFINED_VALUES, /* mapped_menu_op */
 +    0, /* n_menu_mapped */
 +    UNDEFINED_VALUE, /* opt_initial */
 +    UNDEFINED_VALUE, /* opt_from_file */
 +    UNDEFINED_VALUE, /* opt_need_redraw */
 +
 +    /* pickup.c */
 +    0,  /* oldcap */
 +    UNDEFINED_PTR, /* current_container */
 +    UNDEFINED_VALUE, /* abort_looting */
 +    UNDEFINED_VALUE, /* val_for_n_or_more */
 +    UNDEFINED_VALUES, /* valid_menu_classes */
 +    UNDEFINED_VALUE, /* class_filter */
 +    UNDEFINED_VALUE, /* bucx_filter */
 +    UNDEFINED_VALUE, /* shop_filter */
 +
 +    /* pline.c */
 +    0, /* pline_flags */
 +    UNDEFINED_VALUES, /* prevmsg */
 +#ifdef DUMPLOG
 +    0, /* saved_pline_index */
 +    UNDEFINED_VALUES,
 +#endif
 +    NULL, /* you_buf */
 +    0, /* you_buf_siz */
 +
 +    /* polyself.c */
 +    0, /* sex_change_ok */
 +
 +    /* potion.c */
 +    FALSE, /* notonhead */
 +    UNDEFINED_VALUE, /* potion_nothing */
 +    UNDEFINED_VALUE, /* potion_unkn */
 +
 +    /* pray.c */
 +    UNDEFINED_VALUE, /* p_aligntyp */
 +    UNDEFINED_VALUE, /* p_trouble */
 +    UNDEFINED_VALUE, /* p_type */
 +
 +    /* quest.c */
 +    DUMMY, /* quest_status */
 +
 +    /* questpgr.c */
 +    UNDEFINED_VALUES, /* cvt_buf */
 +    UNDEFINED_VALUES, /* qt_list */
 +    UNDEFINED_PTR, /* msg_file */
 +    UNDEFINED_VALUES, /* nambuf */
 +
 +    /* read.c */
 +    UNDEFINED_VALUE, /* known */
 +
 +    /* region.c */
 +    NULL, /* regions */
 +    0, /* n_regions */
 +    0, /* max_regions */
 +
 +    /* restore.c */
 +    0, /* n_ids_mapped */
 +    0, /* id_map */
 +    FALSE, /* restoring */
 +    UNDEFINED_PTR, /* oldfruit */
 +    UNDEFINED_VALUE, /* omoves */
 +
 +    /* rip.c */
 +    UNDEFINED_PTR, /* rip */
 +
 +    /* role.c */
 +    UNDEFINED_VALUES, /* urole */
 +    UNDEFINED_VALUES, /* urace */
 +    UNDEFINED_VALUES, /* role_pa */
 +    UNDEFINED_VALUE, /* role_post_attrib */
 +    UNDEFINED_VALUES, /* rfilter */
 +
 +    /* rumors.c */
 +    0, /* true_rumor_size */
 +    0, /* false_rumor_size */
 +    UNDEFINED_VALUE, /* true_rumor_start*/
 +    UNDEFINED_VALUE, /* false_rumor_start*/
 +    UNDEFINED_VALUE, /* true_rumor_end */
 +    UNDEFINED_VALUE, /* false_rumor_end */
 +    0, /* oracle_flag */
 +    0, /* oracle_cnt */
 +    NULL, /* oracle_loc */
 +
 +    /* save.c */
 +    TRUE, /* havestate*/
 +    0, /* ustuck_id */
 +    0, /* usteed_id */
 +
 +    /* shk.c */
 +    'a', /* sell_response */
 +    SELL_NORMAL, /* sell_how */
 +    FALSE, /* auto_credit */
 +    UNDEFINED_VALUES, /* repo */
 +    UNDEFINED_VALUE, /* followmsg */
 +
 +    /* sp_lev.c */
 +    NULL, /* lev_message */
 +    NULL, /* lregions */
 +    0, /* num_lregions */
 +    UNDEFINED_VALUES, /* SplLev_Map */
 +    UNDEFINED_VALUE, /* xstart */
 +    UNDEFINED_VALUE, /* ystart */
 +    UNDEFINED_VALUE, /* xsize */
 +    UNDEFINED_VALUE, /* ysize */
 +    FALSE, /* splev_init_present */
 +    FALSE, /* icedpools */
 +    0, /* mines_prize_count */
 +    0, /* soki_prize_count */
 +    { UNDEFINED_PTR }, /* container_obj */
 +    0, /* container_idx */
 +    NULL, /* invent_carrying_monster */
 +    { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL }, /* ralign */
 +
 +    /* spells.c */
 +    0, /* spl_sortmode */
 +    NULL, /* spl_orderindx */
 +
 +    /* teleport.c */
 +    NULL, /* telescroll */
 +
 +    /* timeout.c */
 +    UNDEFINED_PTR, /* timer_base */
 +    1, /* timer_id */
 +
 +    /* topten.c */
 +    WIN_ERR, /* topten */
 +#ifdef UPDATE_RECORD_IN_PLACE
 +    UNDEFINED_VALUE, /* final_fpos */
 +#endif
 +
 +    /* trap.c */
 +    0, /* force_mintrap */
 +    { 0, 0, FALSE },
 +    UNDEFINED_VALUES,
 +
 +    /* u_init.c */
 +    STRANGE_OBJECT, /* nocreate */
 +    STRANGE_OBJECT, /* nocreate2 */
 +    STRANGE_OBJECT, /* nocreate3 */
 +    STRANGE_OBJECT, /* nocreate4 */
 +
 +    /* uhitm.c */
 +    UNDEFINED_VALUE, /* override_confirmation */
 +
 +    /* vision.c */
 +    NULL, /* viz_array */
 +    NULL, /* viz_rmin */
 +    NULL, /* viz_rmax */
 +    FALSE, /* vision_full_recalc */
 +
 +    /* weapon.c */
 +    UNDEFINED_PTR, /* propellor */
 +
 +    /* windows.c */
 +    NULL, /* last_winchoice */
 +
 +    /* zap.c */
 +    UNDEFINED_VALUE, /* poly_zap */
 +    UNDEFINED_VALUE,  /* obj_zapped */
 +
 +    IVMAGIC  /* used to validate that structure layout has been preserved */
  };
  
 -struct plinemsg_type *plinemsg_types = (struct plinemsg_type *) 0;
 +struct instance_globals g;
  
 -#ifdef PANICTRACE
 -const char *ARGV0;
 -#endif
 +const struct const_globals cg = {
 +    DUMMY, /* zeroobj */
 +    DUMMY, /* zeromonst */
 +    DUMMY, /* zeroany */
 +};
  
 -/* support for lint.h */
 -unsigned nhUse_dummy = 0;
 +#define ZERO(x) memset(&x, 0, sizeof(x))
  
 -/* dummy routine used to force linkage */
  void
 -decl_init()
 +decl_globals_init()
  {
 -    return;
 +    g = g_init;
 +
 +    g.valuables[0].list = g.gems;
 +    g.valuables[0].size = SIZE(g.gems);
 +    g.valuables[1].list = g.amulets;
 +    g.valuables[1].size = SIZE(g.amulets);
 +    g.valuables[2].list = NULL;
 +    g.valuables[2].size = 0;
 +
 +    if (g_init.magic != IVMAGIC) {
 +        printf("decl_globals_init: g_init.magic in unexpected state (%lx)\n",
 +                g_init.magic);
 +        exit(1);
 +    }
 +
 +    if (g_init.havestate != TRUE) {
 +        printf("decl_globals_init: g_init..havestate not TRUE\n");
 +        exit(1);
 +    }
 +
 +    sfcap = default_sfinfo;
 +    sfrestinfo = default_sfinfo;
 +    sfsaveinfo = default_sfinfo;
 +
 +    g.subrooms = &g.rooms[MAXNROFROOMS + 1];
 +
 +    ZERO(flags);
 +#ifdef SYSFLAGS
 +    ZERO(sysflags);
 +#endif
 +    ZERO(iflags);
 +    ZERO(u);
 +    ZERO(ubirthday);
 +    ZERO(urealtime);
 +
 +    uwep = uarm = uswapwep = uquiver = uarmu = uskin = uarmc = NULL;
 +    uarmh = uarms = uarmg = uarmf = uamul = uright = uleft = NULL;
 +    ublindf = uchain = uball = NULL;
 +
 +    WIN_MESSAGE =  WIN_STATUS =  WIN_MAP = WIN_INVEN = WIN_ERR;
 +
 +    g.urole = urole_init_data;
 +    g.urace = urace_init_data;
 +
 +
  }
  
  /*decl.c*/
diff --cc src/options.c
index 4ed8e46e33dac0a2c7a36f3faa6c03d106d839e8,2e494948a4be6484e00e46ff0d09e88fb662f96e..2ba829eb14433afa08b3559b6df95f19762971b0
@@@ -527,48 -528,58 +527,47 @@@ static const menu_cmd_t default_menu_cm
   { "menu_search", MENU_SEARCH, "Search and toggle matching items" },
  };
  
 -/*
 - * Allow the user to map incoming characters to various menu commands.
 - * The accelerator list must be a valid C string.
 - */
 -#define MAX_MENU_MAPPED_CMDS 32 /* some number */
 -char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */
 -static char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1];
 -static short n_menu_mapped = 0;
 -
 -static boolean initial, from_file;
 -
 -STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
 -STATIC_DCL void FDECL(escapes, (const char *, char *));
 -STATIC_DCL void FDECL(rejectoption, (const char *));
 -STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
 -STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
 -STATIC_DCL void FDECL(bad_negation, (const char *, BOOLEAN_P));
 -STATIC_DCL int FDECL(change_inv_order, (char *));
 -STATIC_DCL boolean FDECL(warning_opts, (char *, const char *));
 -STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *));
 -STATIC_DCL boolean FDECL(duplicate_opt_detection, (const char *, int));
 -STATIC_DCL void FDECL(complain_about_duplicate, (const char *, int));
 -
 -STATIC_DCL const char *FDECL(attr2attrname, (int));
 -STATIC_DCL const char * FDECL(msgtype2name, (int));
 -STATIC_DCL int NDECL(query_msgtype);
 -STATIC_DCL boolean FDECL(msgtype_add, (int, char *));
 -STATIC_DCL void FDECL(free_one_msgtype, (int));
 -STATIC_DCL int NDECL(msgtype_count);
 -STATIC_DCL boolean FDECL(test_regex_pattern, (const char *, const char *));
 -STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
 -STATIC_DCL void FDECL(free_one_menu_coloring, (int));
 -STATIC_DCL int NDECL(count_menucolors);
 -STATIC_DCL boolean FDECL(parse_role_opts, (BOOLEAN_P, const char *,
 +static void FDECL(nmcpy, (char *, const char *, int));
 +static void FDECL(escapes, (const char *, char *));
 +static void FDECL(rejectoption, (const char *));
 +static char *FDECL(string_for_opt, (char *, BOOLEAN_P));
 +static char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
 +static void FDECL(bad_negation, (const char *, BOOLEAN_P));
 +static int FDECL(change_inv_order, (char *));
 +static boolean FDECL(warning_opts, (char *, const char *));
 +static int FDECL(feature_alert_opts, (char *, const char *));
 +static boolean FDECL(duplicate_opt_detection, (const char *, int));
 +static void FDECL(complain_about_duplicate, (const char *, int));
 +
 +static const char *FDECL(attr2attrname, (int));
 +static const char * FDECL(msgtype2name, (int));
 +static int NDECL(query_msgtype);
 +static boolean FDECL(msgtype_add, (int, char *));
 +static void FDECL(free_one_msgtype, (int));
 +static int NDECL(msgtype_count);
 +static boolean FDECL(test_regex_pattern, (const char *, const char *));
 +static boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
 +static void FDECL(free_one_menu_coloring, (int));
 +static int NDECL(count_menucolors);
 +static boolean FDECL(parse_role_opts, (BOOLEAN_P, const char *,
                                             char *, char **));
  
 -STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
 -STATIC_DCL void FDECL(opts_add_others, (winid, const char *, int,
 +static void FDECL(doset_add_menu, (winid, const char *, int));
 +static void FDECL(opts_add_others, (winid, const char *, int,
                                          char *, int));
 -STATIC_DCL int FDECL(handle_add_list_remove, (const char *, int));
 -STATIC_DCL boolean FDECL(special_handling, (const char *,
 +static int FDECL(handle_add_list_remove, (const char *, int));
 +static boolean FDECL(special_handling, (const char *,
                                              BOOLEAN_P, BOOLEAN_P));
 -STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *));
 -STATIC_DCL void FDECL(remove_autopickup_exception,
 +static const char *FDECL(get_compopt_value, (const char *, char *));
 +static void FDECL(remove_autopickup_exception,
                        (struct autopickup_exception *));
- static int FDECL(count_ape_maps, (int *, int *));
  
 -STATIC_DCL boolean FDECL(is_wc_option, (const char *));
 -STATIC_DCL boolean FDECL(wc_supported, (const char *));
 -STATIC_DCL boolean FDECL(is_wc2_option, (const char *));
 -STATIC_DCL boolean FDECL(wc2_supported, (const char *));
 -STATIC_DCL void FDECL(wc_set_font_name, (int, char *));
 -STATIC_DCL int FDECL(wc_set_window_colors, (char *));
 +static boolean FDECL(is_wc_option, (const char *));
 +static boolean FDECL(wc_supported, (const char *));
 +static boolean FDECL(is_wc2_option, (const char *));
 +static boolean FDECL(wc2_supported, (const char *));
 +static void FDECL(wc_set_font_name, (int, char *));
 +static int FDECL(wc_set_window_colors, (char *));
  
  void
  reglyph_darkroom()
@@@ -4352,7 -4413,15 +4351,15 @@@ int nset
  int
  count_apes(VOID_ARGS)
  {
-     return count_ape_maps((int *) 0, (int *) 0);
+     int numapes = 0;
 -    struct autopickup_exception *ape = apelist;
++    struct autopickup_exception *ape = g.apelist;
+     while (ape) {
+       numapes++;
+       ape = ape->next;
+     }
+     return numapes;
  }
  
  enum opt_other_enums {
@@@ -5253,18 -5325,18 +5260,18 @@@ boolean setinitial, setfromfile
  
              tmpwin = create_nhwindow(NHW_MENU);
              start_menu(tmpwin);
-             for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
-                 if (numapes[pass] == 0)
-                     continue;
-                 ape = iflags.autopickup_exceptions[pass];
+             if (numapes) {
 -                ape = apelist;
 -                any = zeroany;
++                ape = g.apelist;
 +                any = cg.zeroany;
                  add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
-                          (pass == 0) ? "Never pickup" : "Always pickup",
+                          "Always pickup '<'; never pickup '>'",
                           MENU_UNSELECTED);
-                 for (i = 0; i < numapes[pass] && ape; i++) {
+                 for (i = 0; i < numapes && ape; i++) {
                      any.a_void = (opt_idx == 1) ? 0 : ape;
-                     /* length of pattern plus quotes is less than BUFSZ */
-                     Sprintf(apebuf, "\"%s\"", ape->pattern);
+                     /* length of pattern plus quotes (plus '<'/'>') is less than
+                        BUFSZ */
+                     Sprintf(apebuf, "\"%c%s\"", ape->grab ? '<' : '>',
+                             ape->pattern);
                      add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf,
                               MENU_UNSELECTED);
                      ape = ape->next;
@@@ -5820,9 -5896,8 +5827,8 @@@ dotogglepickup(
      if (flags.pickup) {
          oc_to_str(flags.pickup_types, ocl);
          Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all",
-                 (iflags.autopickup_exceptions[AP_LEAVE]
-                  || iflags.autopickup_exceptions[AP_GRAB])
-                     ? ((count_ape_maps((int *) 0, (int *) 0) == 1)
 -                (apelist)
++                (g.apelist)
+                     ? ((count_apes() == 1)
                             ? ", with one exception"
                             : ", with some exceptions")
                      : "");
@@@ -5876,10 -5951,8 +5882,8 @@@ const char *mapping
  
      ape->pattern = dupstr(text);
      ape->grab = grab;
-     ape->next = *apehead;
-     *apehead = ape;
 -    ape->next = apelist;
 -    apelist = ape;
++    ape->next = g.apelist;
++    g.apelist = ape;
      return 1;
  }
  
@@@ -5888,16 -5961,15 +5892,15 @@@ remove_autopickup_exception(whichape
  struct autopickup_exception *whichape;
  {
      struct autopickup_exception *ape, *freeape, *prev = 0;
-     int chain = whichape->grab ? AP_GRAB : AP_LEAVE;
  
-     for (ape = iflags.autopickup_exceptions[chain]; ape;) {
 -    for (ape = apelist; ape;) {
++    for (ape = g.apelist; ape;) {
          if (ape == whichape) {
              freeape = ape;
              ape = ape->next;
              if (prev)
                  prev->next = ape;
              else
-                 iflags.autopickup_exceptions[chain] = ape;
 -                apelist = ape;
++                g.apelist = ape;
              regex_free(freeape->regex);
              free((genericptr_t) freeape->pattern);
              free((genericptr_t) freeape);
  void
  free_autopickup_exceptions()
  {
 -    struct autopickup_exception *ape = apelist;
 +    struct autopickup_exception *ape;
-     int pass;
-     for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) {
-         while ((ape = iflags.autopickup_exceptions[pass]) != 0) {
-             regex_free(ape->regex);
-             free((genericptr_t) ape->pattern);
-             iflags.autopickup_exceptions[pass] = ape->next;
-             free((genericptr_t) ape);
-         }
 -    while ((ape = apelist) != 0) {
++    while ((ape = g.apelist) != 0) {
+       regex_free(ape->regex);
+       free((genericptr_t) ape->pattern);
 -      apelist = ape->next;
++      g.apelist = ape->next;
+       free((genericptr_t) ape);
      }
  }
  
diff --cc src/pickup.c
index fde27156e1d057262b5fd69b20d3c999b926d559,ab8d5f0696d4638dd547de6188b4ee81a41101d7..999f34bb1680594f96ec2a336c3c8b2e18e785aa
@@@ -707,9 -718,7 +706,7 @@@ struct obj *obj
      /*
       *  Does the text description of this match an exception?
       */
-     struct autopickup_exception
-         *ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB]
-                       : iflags.autopickup_exceptions[AP_LEAVE];
 -    struct autopickup_exception *ape = apelist;
++    struct autopickup_exception *ape = g.apelist;
  
      if (ape) {
          char *objdesc = makesingular(doname(obj));